| Directory: | ./ |
|---|---|
| File: | sql/handler.cc |
| Date: | 2022-12-13 11:44:05 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 3096 | 3513 | 88.1% |
| Branches: | 3298 | 5652 | 58.4% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* Copyright (c) 2000, 2022, Oracle and/or its affiliates. | ||
| 2 | |||
| 3 | This program is free software; you can redistribute it and/or modify | ||
| 4 | it under the terms of the GNU General Public License, version 2.0, | ||
| 5 | as published by the Free Software Foundation. | ||
| 6 | |||
| 7 | This program is also distributed with certain software (including | ||
| 8 | but not limited to OpenSSL) that is licensed under separate terms, | ||
| 9 | as designated in a particular file or component or in included license | ||
| 10 | documentation. The authors of MySQL hereby grant you an additional | ||
| 11 | permission to link the program and your derivative works with the | ||
| 12 | separately licensed software that they have included with MySQL. | ||
| 13 | |||
| 14 | This program is distributed in the hope that it will be useful, | ||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | GNU General Public License, version 2.0, for more details. | ||
| 18 | |||
| 19 | You should have received a copy of the GNU General Public License | ||
| 20 | along with this program; if not, write to the Free Software | ||
| 21 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
| 22 | |||
| 23 | /** @file sql/handler.cc | ||
| 24 | |||
| 25 | @brief | ||
| 26 | Implements functions in the handler interface that are shared between all | ||
| 27 | storage engines. | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include "sql/handler.h" | ||
| 31 | |||
| 32 | #include <ctype.h> | ||
| 33 | #include <errno.h> | ||
| 34 | #include <limits.h> | ||
| 35 | #include <stdio.h> | ||
| 36 | #include <stdlib.h> | ||
| 37 | #include <algorithm> | ||
| 38 | #include <atomic> | ||
| 39 | #include <cmath> | ||
| 40 | #include <list> | ||
| 41 | #include <random> // std::uniform_real_distribution | ||
| 42 | #include <string> | ||
| 43 | #include <string_view> | ||
| 44 | #include <vector> | ||
| 45 | |||
| 46 | #include "keycache.h" | ||
| 47 | #include "libbinlogevents/include/binlog_event.h" | ||
| 48 | #include "m_ctype.h" | ||
| 49 | #include "m_string.h" | ||
| 50 | #include "my_bit.h" // my_count_bits | ||
| 51 | #include "my_bitmap.h" // MY_BITMAP | ||
| 52 | #include "my_check_opt.h" | ||
| 53 | #include "my_dbug.h" | ||
| 54 | #include "my_loglevel.h" | ||
| 55 | #include "my_macros.h" | ||
| 56 | #include "my_pointer_arithmetic.h" | ||
| 57 | #include "my_psi_config.h" | ||
| 58 | #include "my_sqlcommand.h" | ||
| 59 | #include "my_sys.h" // MEM_DEFINED_IF_ADDRESSABLE() | ||
| 60 | #include "myisam.h" // TT_FOR_UPGRADE | ||
| 61 | #include "mysql/components/services/bits/psi_bits.h" | ||
| 62 | #include "mysql/components/services/log_builtins.h" | ||
| 63 | #include "mysql/components/services/log_shared.h" | ||
| 64 | #include "mysql/plugin.h" | ||
| 65 | #include "mysql/psi/mysql_file.h" | ||
| 66 | #include "mysql/psi/mysql_mutex.h" | ||
| 67 | #include "mysql/psi/mysql_table.h" | ||
| 68 | #include "mysql/psi/mysql_transaction.h" | ||
| 69 | #include "mysql/psi/psi_table.h" | ||
| 70 | #include "mysql/service_mysql_alloc.h" | ||
| 71 | #include "mysql_com.h" | ||
| 72 | #include "mysql_version.h" // MYSQL_VERSION_ID | ||
| 73 | #include "mysqld_error.h" | ||
| 74 | #include "prealloced_array.h" | ||
| 75 | #include "sql/auth/auth_common.h" // check_readonly() and SUPER_ACL | ||
| 76 | #include "sql/binlog.h" // mysql_bin_log | ||
| 77 | #include "sql/check_stack.h" | ||
| 78 | #include "sql/clone_handler.h" | ||
| 79 | #include "sql/current_thd.h" | ||
| 80 | #include "sql/dd/cache/dictionary_client.h" // dd::cache::Dictionary_client | ||
| 81 | #include "sql/dd/dd.h" // dd::get_dictionary | ||
| 82 | #include "sql/dd/dictionary.h" // dd:acquire_shared_table_mdl | ||
| 83 | #include "sql/dd/types/table.h" // dd::Table | ||
| 84 | #include "sql/dd_table_share.h" // open_table_def | ||
| 85 | #include "sql/debug_sync.h" // DEBUG_SYNC | ||
| 86 | #include "sql/derror.h" // ER_DEFAULT | ||
| 87 | #include "sql/error_handler.h" // Internal_error_handler | ||
| 88 | #include "sql/field.h" | ||
| 89 | #include "sql/item.h" | ||
| 90 | #include "sql/lock.h" // MYSQL_LOCK | ||
| 91 | #include "sql/log.h" | ||
| 92 | #include "sql/log_event.h" // Write_rows_log_event | ||
| 93 | #include "sql/mdl.h" | ||
| 94 | #include "sql/mysqld.h" // global_system_variables heap_hton .. | ||
| 95 | #include "sql/mysqld_thd_manager.h" | ||
| 96 | #include "sql/opt_costconstantcache.h" // reload_optimizer_cost_constants | ||
| 97 | #include "sql/opt_costmodel.h" | ||
| 98 | #include "sql/opt_hints.h" | ||
| 99 | #include "sql/protocol.h" | ||
| 100 | #include "sql/psi_memory_key.h" | ||
| 101 | #include "sql/query_options.h" | ||
| 102 | #include "sql/record_buffer.h" // Record_buffer | ||
| 103 | #include "sql/rpl_filter.h" | ||
| 104 | #include "sql/rpl_gtid.h" | ||
| 105 | #include "sql/rpl_handler.h" // RUN_HOOK | ||
| 106 | #include "sql/rpl_replica_commit_order_manager.h" // Commit_order_manager | ||
| 107 | #include "sql/rpl_rli.h" // is_atomic_ddl_commit_on_slave | ||
| 108 | #include "sql/rpl_write_set_handler.h" // add_pke | ||
| 109 | #include "sql/sdi_utils.h" // import_serialized_meta_data | ||
| 110 | #include "sql/session_tracker.h" | ||
| 111 | #include "sql/sql_base.h" // free_io_cache | ||
| 112 | #include "sql/sql_bitmap.h" | ||
| 113 | #include "sql/sql_class.h" | ||
| 114 | #include "sql/sql_error.h" | ||
| 115 | #include "sql/sql_lex.h" | ||
| 116 | #include "sql/sql_parse.h" // check_stack_overrun | ||
| 117 | #include "sql/sql_plugin.h" // plugin_foreach | ||
| 118 | #include "sql/sql_select.h" // actual_key_parts | ||
| 119 | #include "sql/sql_table.h" // build_table_filename | ||
| 120 | #include "sql/sql_zip_dict.h" | ||
| 121 | #include "sql/strfunc.h" // strnncmp_nopads | ||
| 122 | #include "sql/system_variables.h" | ||
| 123 | #include "sql/table.h" | ||
| 124 | #include "sql/tc_log.h" | ||
| 125 | #include "sql/thr_malloc.h" | ||
| 126 | #include "sql/transaction.h" // trans_commit_implicit | ||
| 127 | #include "sql/transaction_info.h" | ||
| 128 | #include "sql/xa.h" | ||
| 129 | #include "sql/xa/sql_cmd_xa.h" // Sql_cmd_xa_* | ||
| 130 | #include "sql_string.h" | ||
| 131 | #include "sql_tmp_table.h" // free_tmp_table | ||
| 132 | #include "template_utils.h" | ||
| 133 | #include "uniques.h" // Unique_on_insert | ||
| 134 | #include "varlen_sort.h" | ||
| 135 | |||
| 136 | /** | ||
| 137 | @def MYSQL_TABLE_IO_WAIT | ||
| 138 | Instrumentation helper for table io_waits. | ||
| 139 | Note that this helper is intended to be used from | ||
| 140 | within the handler class only, as it uses members | ||
| 141 | from @c handler | ||
| 142 | Performance schema events are instrumented as follows: | ||
| 143 | - in non batch mode, one event is generated per call | ||
| 144 | - in batch mode, the number of rows affected is saved | ||
| 145 | in @c m_psi_numrows, so that @c end_psi_batch_mode() | ||
| 146 | generates a single event for the batch. | ||
| 147 | @param OP the table operation to be performed | ||
| 148 | @param INDEX the table index used if any, or MAX_KEY. | ||
| 149 | @param RESULT the result of the table operation performed | ||
| 150 | @param PAYLOAD instrumented code to execute | ||
| 151 | @sa handler::end_psi_batch_mode. | ||
| 152 | */ | ||
| 153 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 154 | #define MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD) \ | ||
| 155 | { \ | ||
| 156 | if (m_psi != NULL) { \ | ||
| 157 | switch (m_psi_batch_mode) { \ | ||
| 158 | case PSI_BATCH_MODE_NONE: { \ | ||
| 159 | PSI_table_locker *sub_locker = NULL; \ | ||
| 160 | PSI_table_locker_state reentrant_safe_state; \ | ||
| 161 | reentrant_safe_state.m_thread = nullptr; \ | ||
| 162 | reentrant_safe_state.m_wait = nullptr; \ | ||
| 163 | sub_locker = PSI_TABLE_CALL(start_table_io_wait)( \ | ||
| 164 | &reentrant_safe_state, m_psi, OP, INDEX, __FILE__, __LINE__); \ | ||
| 165 | PAYLOAD \ | ||
| 166 | if (sub_locker != NULL) PSI_TABLE_CALL(end_table_io_wait) \ | ||
| 167 | (sub_locker, 1); \ | ||
| 168 | break; \ | ||
| 169 | } \ | ||
| 170 | case PSI_BATCH_MODE_STARTING: { \ | ||
| 171 | m_psi_locker = PSI_TABLE_CALL(start_table_io_wait)( \ | ||
| 172 | &m_psi_locker_state, m_psi, OP, INDEX, __FILE__, __LINE__); \ | ||
| 173 | PAYLOAD \ | ||
| 174 | if (RESULT != HA_ERR_END_OF_FILE) m_psi_numrows++; \ | ||
| 175 | m_psi_batch_mode = PSI_BATCH_MODE_STARTED; \ | ||
| 176 | break; \ | ||
| 177 | } \ | ||
| 178 | case PSI_BATCH_MODE_STARTED: \ | ||
| 179 | default: { \ | ||
| 180 | assert(m_psi_batch_mode == PSI_BATCH_MODE_STARTED); \ | ||
| 181 | PAYLOAD \ | ||
| 182 | if (RESULT != HA_ERR_END_OF_FILE) m_psi_numrows++; \ | ||
| 183 | break; \ | ||
| 184 | } \ | ||
| 185 | } \ | ||
| 186 | } else { \ | ||
| 187 | PAYLOAD \ | ||
| 188 | } \ | ||
| 189 | } | ||
| 190 | #else | ||
| 191 | #define MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD) PAYLOAD | ||
| 192 | #endif | ||
| 193 | |||
| 194 | /** | ||
| 195 | @def MYSQL_TABLE_LOCK_WAIT | ||
| 196 | Instrumentation helper for table io_waits. | ||
| 197 | @param OP the table operation to be performed | ||
| 198 | @param FLAGS per table operation flags. | ||
| 199 | @param PAYLOAD the code to instrument. | ||
| 200 | @sa MYSQL_END_TABLE_WAIT. | ||
| 201 | */ | ||
| 202 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 203 | #define MYSQL_TABLE_LOCK_WAIT(OP, FLAGS, PAYLOAD) \ | ||
| 204 | { \ | ||
| 205 | if (m_psi != NULL) { \ | ||
| 206 | PSI_table_locker *locker; \ | ||
| 207 | PSI_table_locker_state state; \ | ||
| 208 | locker = PSI_TABLE_CALL(start_table_lock_wait)(&state, m_psi, OP, FLAGS, \ | ||
| 209 | __FILE__, __LINE__); \ | ||
| 210 | PAYLOAD \ | ||
| 211 | if (locker != NULL) PSI_TABLE_CALL(end_table_lock_wait)(locker); \ | ||
| 212 | } else { \ | ||
| 213 | PAYLOAD \ | ||
| 214 | } \ | ||
| 215 | } | ||
| 216 | #else | ||
| 217 | #define MYSQL_TABLE_LOCK_WAIT(OP, FLAGS, PAYLOAD) PAYLOAD | ||
| 218 | #endif | ||
| 219 | |||
| 220 | using std::list; | ||
| 221 | using std::log2; | ||
| 222 | using std::max; | ||
| 223 | using std::min; | ||
| 224 | |||
| 225 | #ifdef WITH_WSREP | ||
| 226 | #include "wsrep_mysqld.h" | ||
| 227 | #include "wsrep_thd.h" | ||
| 228 | #include "wsrep_trans_observer.h" /* wsrep transaction hooks */ | ||
| 229 | #include "wsrep_xid.h" | ||
| 230 | #endif /* WITH_WSREP */ | ||
| 231 | |||
| 232 | /** | ||
| 233 | While we have legacy_db_type, we have this array to | ||
| 234 | check for dups and to find handlerton from legacy_db_type. | ||
| 235 | Remove when legacy_db_type is finally gone | ||
| 236 | */ | ||
| 237 | static Prealloced_array<st_plugin_int *, PREALLOC_NUM_HA> se_plugin_array( | ||
| 238 | PSI_NOT_INSTRUMENTED); | ||
| 239 | |||
| 240 | /** | ||
| 241 | Array allowing to check if handlerton is builtin without | ||
| 242 | acquiring LOCK_plugin. | ||
| 243 | */ | ||
| 244 | static Prealloced_array<bool, PREALLOC_NUM_HA> builtin_htons( | ||
| 245 | PSI_NOT_INSTRUMENTED); | ||
| 246 | |||
| 247 | 4156503 | st_plugin_int *hton2plugin(uint slot) { return se_plugin_array[slot]; } | |
| 248 | |||
| 249 | 144208 | size_t num_hton2plugins() { return se_plugin_array.size(); } | |
| 250 | |||
| 251 | 27 | st_plugin_int *insert_hton2plugin(uint slot, st_plugin_int *plugin) { | |
| 252 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
|
27 | if (se_plugin_array.assign_at(slot, plugin)) return nullptr; |
| 253 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | builtin_htons.assign_at(slot, true); |
| 254 | 27 | return se_plugin_array[slot]; | |
| 255 | } | ||
| 256 | |||
| 257 | 27 | st_plugin_int *remove_hton2plugin(uint slot) { | |
| 258 | 27 | st_plugin_int *retval = se_plugin_array[slot]; | |
| 259 | 27 | se_plugin_array[slot] = NULL; | |
| 260 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | builtin_htons.assign_at(slot, false); |
| 261 | 27 | return retval; | |
| 262 | } | ||
| 263 | |||
| 264 | 1841199 | const char *ha_resolve_storage_engine_name(const handlerton *db_type) { | |
| 265 |
1/2✓ Branch 0 taken 1841199 times.
✗ Branch 1 not taken.
|
1841199 | return db_type == nullptr ? "UNKNOWN" : hton2plugin(db_type->slot)->name.str; |
| 266 | } | ||
| 267 | |||
| 268 | static handlerton *installed_htons[128]; | ||
| 269 | |||
| 270 | /* number of storage engines (from installed_htons[]) that support 2pc */ | ||
| 271 | ulong total_ha_2pc = 0; | ||
| 272 | /* size of savepoint storage area (see ha_init) */ | ||
| 273 | ulong savepoint_alloc_size = 0; | ||
| 274 | |||
| 275 | namespace { | ||
| 276 | struct Storage_engine_identifier { | ||
| 277 | const LEX_CSTRING canonical; | ||
| 278 | const LEX_CSTRING legacy; | ||
| 279 | }; | ||
| 280 | const Storage_engine_identifier se_names[] = { | ||
| 281 | {{STRING_WITH_LEN("INNODB")}, {STRING_WITH_LEN("INNOBASE")}}, | ||
| 282 | {{STRING_WITH_LEN("NDBCLUSTER")}, {STRING_WITH_LEN("NDB")}}, | ||
| 283 | {{STRING_WITH_LEN("MEMORY")}, {STRING_WITH_LEN("HEAP")}}, | ||
| 284 | {{STRING_WITH_LEN("MRG_MYISAM")}, {STRING_WITH_LEN("MERGE")}}}; | ||
| 285 | const auto se_names_end = std::end(se_names); | ||
| 286 | std::vector<std::string> disabled_se_names; | ||
| 287 | } // namespace | ||
| 288 | |||
| 289 | const char *ha_row_type[] = {"", | ||
| 290 | "FIXED", | ||
| 291 | "DYNAMIC", | ||
| 292 | "COMPRESSED", | ||
| 293 | "REDUNDANT", | ||
| 294 | "COMPACT", | ||
| 295 | /* Reserved to be "PAGE" in future versions */ "?", | ||
| 296 | "?", | ||
| 297 | "?", | ||
| 298 | "?"}; | ||
| 299 | |||
| 300 | const char *tx_isolation_names[] = {"READ-UNCOMMITTED", "READ-COMMITTED", | ||
| 301 | "REPEATABLE-READ", "SERIALIZABLE", NullS}; | ||
| 302 | TYPELIB tx_isolation_typelib = {array_elements(tx_isolation_names) - 1, "", | ||
| 303 | tx_isolation_names, nullptr}; | ||
| 304 | |||
| 305 | // Called for each SE to check if given db.table_name is a system table. | ||
| 306 | static bool check_engine_system_table_handlerton(THD *unused, plugin_ref plugin, | ||
| 307 | void *arg); | ||
| 308 | |||
| 309 | static int ha_discover(THD *thd, const char *db, const char *name, | ||
| 310 | uchar **frmblob, size_t *frmlen); | ||
| 311 | |||
| 312 | /** | ||
| 313 | Structure used by SE during check for system table. | ||
| 314 | This structure is passed to each SE handlerton and the status (OUT param) | ||
| 315 | is collected. | ||
| 316 | */ | ||
| 317 | struct st_sys_tbl_chk_params { | ||
| 318 | const char *db; // IN param | ||
| 319 | const char *table_name; // IN param | ||
| 320 | bool is_sql_layer_system_table; // IN param | ||
| 321 | legacy_db_type db_type; // IN param | ||
| 322 | |||
| 323 | enum enum_sys_tbl_chk_status { | ||
| 324 | // db.table_name is not a supported system table. | ||
| 325 | NOT_KNOWN_SYSTEM_TABLE, | ||
| 326 | /* | ||
| 327 | db.table_name is a system table, | ||
| 328 | but may not be supported by SE. | ||
| 329 | */ | ||
| 330 | KNOWN_SYSTEM_TABLE, | ||
| 331 | /* | ||
| 332 | db.table_name is a system table, | ||
| 333 | and is supported by SE. | ||
| 334 | */ | ||
| 335 | SUPPORTED_SYSTEM_TABLE | ||
| 336 | } status; // OUT param | ||
| 337 | }; | ||
| 338 | |||
| 339 | 1396682 | static plugin_ref ha_default_plugin(THD *thd) { | |
| 340 |
2/2✓ Branch 0 taken 1394676 times.
✓ Branch 1 taken 2006 times.
|
1396682 | if (thd->variables.table_plugin) return thd->variables.table_plugin; |
| 341 | 2006 | return my_plugin_lock(thd, &global_system_variables.table_plugin); | |
| 342 | } | ||
| 343 | |||
| 344 | /** @brief | ||
| 345 | Return the default storage engine handlerton used for non-temp tables | ||
| 346 | for thread | ||
| 347 | |||
| 348 | SYNOPSIS | ||
| 349 | ha_default_handlerton(thd) | ||
| 350 | thd current thread | ||
| 351 | |||
| 352 | RETURN | ||
| 353 | pointer to handlerton | ||
| 354 | */ | ||
| 355 | 1396682 | handlerton *ha_default_handlerton(THD *thd) { | |
| 356 | 1396682 | plugin_ref plugin = ha_default_plugin(thd); | |
| 357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1396682 times.
|
1396682 | assert(plugin); |
| 358 | 1396682 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 359 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1396682 times.
|
1396682 | assert(hton); |
| 360 | 1396682 | return hton; | |
| 361 | } | ||
| 362 | |||
| 363 | /** @brief | ||
| 364 | Return the enforced storage engine handlerton for thread | ||
| 365 | |||
| 366 | SYNOPSIS | ||
| 367 | ha_enforce_handlerton(thd) | ||
| 368 | thd current thread | ||
| 369 | |||
| 370 | RETURN | ||
| 371 | pointer to handlerton | ||
| 372 | */ | ||
| 373 | 46 | handlerton *ha_enforce_handlerton(THD *thd) { | |
| 374 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | if (enforce_storage_engine) { |
| 375 | const LEX_CSTRING name{enforce_storage_engine, | ||
| 376 | 46 | strlen(enforce_storage_engine)}; | |
| 377 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | plugin_ref plugin = ha_resolve_by_name(thd, &name, false); |
| 378 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | if (plugin) { |
| 379 | 46 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 380 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | assert(hton); |
| 381 | 46 | return hton; | |
| 382 | } else { | ||
| 383 | ✗ | my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), enforce_storage_engine, | |
| 384 | enforce_storage_engine); | ||
| 385 | } | ||
| 386 | } | ||
| 387 | ✗ | return nullptr; | |
| 388 | } | ||
| 389 | |||
| 390 | 206108 | static plugin_ref ha_default_temp_plugin(THD *thd) { | |
| 391 |
2/2✓ Branch 0 taken 206100 times.
✓ Branch 1 taken 8 times.
|
206108 | if (thd->variables.temp_table_plugin) return thd->variables.temp_table_plugin; |
| 392 | 8 | return my_plugin_lock(thd, &global_system_variables.temp_table_plugin); | |
| 393 | } | ||
| 394 | |||
| 395 | /** @brief | ||
| 396 | Return the default storage engine handlerton used for explicitly | ||
| 397 | created temp tables for a thread | ||
| 398 | |||
| 399 | SYNOPSIS | ||
| 400 | ha_default_temp_handlerton(thd) | ||
| 401 | thd current thread | ||
| 402 | |||
| 403 | RETURN | ||
| 404 | pointer to handlerton | ||
| 405 | */ | ||
| 406 | 206108 | handlerton *ha_default_temp_handlerton(THD *thd) { | |
| 407 | 206108 | plugin_ref plugin = ha_default_temp_plugin(thd); | |
| 408 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 206108 times.
|
206108 | assert(plugin); |
| 409 | 206108 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 410 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 206108 times.
|
206108 | assert(hton); |
| 411 | 206108 | return hton; | |
| 412 | } | ||
| 413 | |||
| 414 | /** | ||
| 415 | Resolve handlerton plugin by name, without checking for "DEFAULT" or | ||
| 416 | HTON_NOT_USER_SELECTABLE. | ||
| 417 | |||
| 418 | @param thd Thread context. | ||
| 419 | @param name Plugin name. | ||
| 420 | |||
| 421 | @return plugin or NULL if not found. | ||
| 422 | */ | ||
| 423 | 5663505 | plugin_ref ha_resolve_by_name_raw(THD *thd, const LEX_CSTRING &name) { | |
| 424 | 5663505 | return plugin_lock_by_name(thd, name, MYSQL_STORAGE_ENGINE_PLUGIN); | |
| 425 | } | ||
| 426 | |||
| 427 | 590606 | static const CHARSET_INFO &hton_charset() { return *system_charset_info; } | |
| 428 | |||
| 429 | /** | ||
| 430 | Return the storage engine handlerton for the supplied name. | ||
| 431 | |||
| 432 | @param thd Current thread. May be nullptr, (e.g. during initialize). | ||
| 433 | @param name Name of storage engine. | ||
| 434 | @param is_temp_table true if table is a temporary table. | ||
| 435 | |||
| 436 | @return Pointer to storage engine plugin handle. | ||
| 437 | */ | ||
| 438 | 608299 | plugin_ref ha_resolve_by_name(THD *thd, const LEX_CSTRING *name, | |
| 439 | bool is_temp_table) { | ||
| 440 |
5/8✓ Branch 0 taken 588665 times.
✓ Branch 1 taken 19634 times.
✓ Branch 2 taken 588666 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 588666 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 608300 times.
|
608299 | if (thd && 0 == strnncmp_nopads(hton_charset(), *name, |
| 441 | {STRING_WITH_LEN("DEFAULT")})) { | ||
| 442 | ✗ | return is_temp_table ? ha_default_plugin(thd) : ha_default_temp_plugin(thd); | |
| 443 | } | ||
| 444 | |||
| 445 | // Note that thd CAN be nullptr here - it is not actually needed by | ||
| 446 | // ha_resolve_by_name_raw(). | ||
| 447 | 608300 | plugin_ref plugin = ha_resolve_by_name_raw(thd, *name); | |
| 448 |
2/2✓ Branch 0 taken 499 times.
✓ Branch 1 taken 607801 times.
|
608300 | if (plugin == nullptr) { |
| 449 | // If we fail to resolve the name passed in, we try to see if it is a | ||
| 450 | // historical alias. | ||
| 451 |
2/2✓ Branch 0 taken 394 times.
✓ Branch 1 taken 105 times.
|
499 | auto match = std::find_if( |
| 452 | std::begin(se_names), se_names_end, | ||
| 453 | 1695 | [&](const Storage_engine_identifier &sei) { | |
| 454 | 1695 | return (0 == strnncmp_nopads(hton_charset(), *name, sei.legacy)); | |
| 455 | }); | ||
| 456 |
2/2✓ Branch 0 taken 394 times.
✓ Branch 1 taken 105 times.
|
499 | if (match != se_names_end) { |
| 457 | // if it is, we resolve using the new name | ||
| 458 | 394 | plugin = ha_resolve_by_name_raw(thd, match->canonical); | |
| 459 | } | ||
| 460 | } | ||
| 461 |
2/2✓ Branch 0 taken 608195 times.
✓ Branch 1 taken 105 times.
|
608300 | if (plugin != nullptr) { |
| 462 | 608195 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 463 |
2/4✓ Branch 0 taken 608195 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 608195 times.
✗ Branch 3 not taken.
|
608195 | if (hton && !(hton->flags & HTON_NOT_USER_SELECTABLE)) return plugin; |
| 464 | |||
| 465 | /* | ||
| 466 | unlocking plugin immediately after locking is relatively low cost. | ||
| 467 | */ | ||
| 468 | ✗ | plugin_unlock(thd, plugin); | |
| 469 | } | ||
| 470 | 105 | return nullptr; | |
| 471 | } | ||
| 472 | |||
| 473 | /** | ||
| 474 | Read a comma-separated list of storage engine names. Look up each in the | ||
| 475 | known list of canonical and legacy names. In case of a match; add both the | ||
| 476 | canonical and the legacy name to disabled_se_names, which is a static vector | ||
| 477 | of disabled storage engine names. | ||
| 478 | If there is no match, the unmodified name is added to the vector. | ||
| 479 | */ | ||
| 480 | 9359 | void set_externally_disabled_storage_engine_names(const char *disabled_list) { | |
| 481 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9359 times.
|
9359 | assert(disabled_list != nullptr); |
| 482 | |||
| 483 | 18718 | myu::Split( | |
| 484 |
1/2✓ Branch 0 taken 9359 times.
✗ Branch 1 not taken.
|
9359 | disabled_list, disabled_list + strlen(disabled_list), myu::IsComma, |
| 485 | 12 | [](const char *f, const char *l) { | |
| 486 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | auto tr = myu::FindTrimmedRange(f, l, myu::IsSpace); |
| 487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
17 | if (tr.first == tr.second) return; |
| 488 | |||
| 489 | 12 | const LEX_CSTRING dse{tr.first, | |
| 490 | 12 | static_cast<size_t>(tr.second - tr.first)}; | |
| 491 |
3/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 7 times.
|
12 | auto match = std::find_if( |
| 492 | std::begin(se_names), se_names_end, | ||
| 493 | 33 | [&](const Storage_engine_identifier &seid) { | |
| 494 | return ( | ||
| 495 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 4 times.
|
62 | (0 == strnncmp_nopads(hton_charset(), dse, seid.canonical)) || |
| 496 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 26 times.
|
62 | (0 == strnncmp_nopads(hton_charset(), dse, seid.legacy))); |
| 497 | }); | ||
| 498 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
|
12 | if (match == se_names_end) { |
| 499 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | disabled_se_names.emplace_back(dse.str, dse.length); |
| 500 | 5 | return; | |
| 501 | } | ||
| 502 | 7 | disabled_se_names.emplace_back(match->canonical.str, | |
| 503 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | match->canonical.length); |
| 504 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | disabled_se_names.emplace_back(match->legacy.str, match->legacy.length); |
| 505 | }); | ||
| 506 | 9359 | } | |
| 507 | |||
| 508 | 646828 | static bool is_storage_engine_name_externally_disabled(const char *name) { | |
| 509 | 646828 | const LEX_CSTRING n{name, strlen(name)}; | |
| 510 |
1/2✓ Branch 0 taken 646828 times.
✗ Branch 1 not taken.
|
646828 | return std::any_of( |
| 511 | disabled_se_names.begin(), disabled_se_names.end(), | ||
| 512 | 184 | [&](const std::string &dse) { | |
| 513 |
1/2✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
|
184 | return (0 == strnncmp_nopads(hton_charset(), n, |
| 514 | 368 | {dse.c_str(), dse.length()})); | |
| 515 | 1293656 | }); | |
| 516 | } | ||
| 517 | |||
| 518 | /** | ||
| 519 | Returns true if the storage engine of the handlerton argument has | ||
| 520 | been listed in the disabled_storage_engines system variable. @note | ||
| 521 | that the SE may still be internally enabled, that is | ||
| 522 | HaIsInternallyEnabled may return true. | ||
| 523 | */ | ||
| 524 | 646828 | bool ha_is_externally_disabled(const handlerton &htnr) { | |
| 525 | 646828 | const char *se_name = ha_resolve_storage_engine_name(&htnr); | |
| 526 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 646828 times.
|
646828 | assert(se_name != nullptr); |
| 527 | 646828 | return is_storage_engine_name_externally_disabled(se_name); | |
| 528 | } | ||
| 529 | |||
| 530 | // Check if storage engine is disabled for table/tablespace creation. | ||
| 531 | 27277 | bool ha_is_storage_engine_disabled(handlerton *se_handle) { | |
| 532 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27277 times.
|
27277 | assert(se_handle != nullptr); |
| 533 | 27277 | return ha_is_externally_disabled(*se_handle); | |
| 534 | } | ||
| 535 | |||
| 536 | 1582761 | plugin_ref ha_lock_engine(THD *thd, const handlerton *hton) { | |
| 537 |
2/2✓ Branch 0 taken 1543646 times.
✓ Branch 1 taken 39115 times.
|
1582761 | if (hton) { |
| 538 |
1/2✓ Branch 0 taken 1543646 times.
✗ Branch 1 not taken.
|
1543646 | st_plugin_int **plugin = &se_plugin_array[hton->slot]; |
| 539 | |||
| 540 | #ifdef NDEBUG | ||
| 541 | /* | ||
| 542 | Take a shortcut for builtin engines -- return pointer to plugin | ||
| 543 | without acquiring LOCK_plugin mutex. This is safe safe since such | ||
| 544 | plugins are not deleted until shutdown and we don't do reference | ||
| 545 | counting in non-debug builds for them. | ||
| 546 | |||
| 547 | Since we have reference to handlerton on our hands, this method | ||
| 548 | can't be called concurrently to non-builtin handlerton initialization/ | ||
| 549 | deinitialization. So it is safe to access builtin_htons[] without | ||
| 550 | additional locking. | ||
| 551 | */ | ||
| 552 | if (builtin_htons[hton->slot]) return *plugin; | ||
| 553 | |||
| 554 | return my_plugin_lock(thd, plugin); | ||
| 555 | #else | ||
| 556 | /* | ||
| 557 | We can't take shortcut in debug builds. | ||
| 558 | At least assert that builtin_htons[slot] is set correctly. | ||
| 559 | */ | ||
| 560 |
2/4✓ Branch 0 taken 1543646 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1543646 times.
|
1543646 | assert(builtin_htons[hton->slot] == (plugin[0]->plugin_dl == nullptr)); |
| 561 |
1/2✓ Branch 0 taken 1543647 times.
✗ Branch 1 not taken.
|
1543646 | return my_plugin_lock(thd, &plugin); |
| 562 | #endif | ||
| 563 | } | ||
| 564 | 39115 | return nullptr; | |
| 565 | } | ||
| 566 | |||
| 567 | 572463 | handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type) { | |
| 568 | plugin_ref plugin; | ||
| 569 |
3/3✓ Branch 0 taken 2798 times.
✓ Branch 1 taken 472864 times.
✓ Branch 2 taken 96801 times.
|
572463 | switch (db_type) { |
| 570 | 2798 | case DB_TYPE_DEFAULT: | |
| 571 | 2798 | return ha_default_handlerton(thd); | |
| 572 | 472864 | default: | |
| 573 |
4/6✓ Branch 0 taken 472864 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 472864 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 472854 times.
✓ Branch 5 taken 11 times.
|
945729 | if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT && |
| 574 |
2/2✓ Branch 0 taken 472854 times.
✓ Branch 1 taken 11 times.
|
472864 | (plugin = ha_lock_engine(thd, installed_htons[db_type]))) |
| 575 | 472854 | return plugin_data<handlerton *>(plugin); | |
| 576 | [[fallthrough]]; | ||
| 577 | case DB_TYPE_UNKNOWN: | ||
| 578 | 96812 | return nullptr; | |
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 582 | /** | ||
| 583 | Use other database handler if databasehandler is not compiled in. | ||
| 584 | */ | ||
| 585 | 104757 | handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type, | |
| 586 | bool no_substitute, bool report_error) { | ||
| 587 |
1/2✓ Branch 0 taken 104757 times.
✗ Branch 1 not taken.
|
104757 | DBUG_TRACE; |
| 588 |
1/2✓ Branch 0 taken 104757 times.
✗ Branch 1 not taken.
|
104757 | handlerton *hton = ha_resolve_by_legacy_type(thd, database_type); |
| 589 |
2/2✓ Branch 0 taken 7945 times.
✓ Branch 1 taken 96812 times.
|
104757 | if (ha_storage_engine_is_enabled(hton)) return hton; |
| 590 | |||
| 591 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96812 times.
|
96812 | if (no_substitute) { |
| 592 | ✗ | if (report_error) { | |
| 593 | ✗ | const char *engine_name = ha_resolve_storage_engine_name(hton); | |
| 594 | ✗ | my_error(ER_FEATURE_DISABLED, MYF(0), engine_name, engine_name); | |
| 595 | } | ||
| 596 | ✗ | return nullptr; | |
| 597 | } | ||
| 598 | |||
| 599 | #ifdef WITH_WSREP | ||
| 600 |
1/2✓ Branch 0 taken 96812 times.
✗ Branch 1 not taken.
|
96812 | (void)wsrep_after_rollback(thd, false); |
| 601 | #endif /* WITH_WSREP */ | ||
| 602 | |||
| 603 |
4/6✓ Branch 0 taken 96812 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 826 times.
✓ Branch 3 taken 95986 times.
✓ Branch 4 taken 826 times.
✗ Branch 5 not taken.
|
96812 | (void)RUN_HOOK(transaction, after_rollback, (thd, false)); |
| 604 | |||
| 605 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96812 times.
|
96812 | switch (database_type) { |
| 606 | ✗ | case DB_TYPE_MRG_ISAM: | |
| 607 | ✗ | return ha_resolve_by_legacy_type(thd, DB_TYPE_MRG_MYISAM); | |
| 608 | 96812 | default: | |
| 609 | 96812 | break; | |
| 610 | } | ||
| 611 | |||
| 612 |
1/2✓ Branch 0 taken 96812 times.
✗ Branch 1 not taken.
|
96812 | return ha_default_handlerton(thd); |
| 613 | 104757 | } /* ha_checktype */ | |
| 614 | |||
| 615 | /** | ||
| 616 | Create handler object for the table in the storage engine. | ||
| 617 | |||
| 618 | @param share TABLE_SHARE for the table, can be NULL if caller | ||
| 619 | didn't perform full-blown open of table definition. | ||
| 620 | @param partitioned Indicates whether table is partitioned. | ||
| 621 | @param alloc Memory root to be used for allocating handler object. | ||
| 622 | @param db_type Table's storage engine. | ||
| 623 | |||
| 624 | @note This function will try to use default storage engine if one which | ||
| 625 | was specified through db_type parameter is not available. | ||
| 626 | */ | ||
| 627 | 12221996 | handler *get_new_handler(TABLE_SHARE *share, bool partitioned, MEM_ROOT *alloc, | |
| 628 | handlerton *db_type) { | ||
| 629 | handler *file; | ||
| 630 |
1/2✓ Branch 0 taken 12222011 times.
✗ Branch 1 not taken.
|
12221996 | DBUG_TRACE; |
| 631 |
5/8✓ Branch 0 taken 12222006 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12222008 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 340 times.
✓ Branch 5 taken 12221668 times.
✓ Branch 6 taken 340 times.
✗ Branch 7 not taken.
|
12222011 | DBUG_PRINT("enter", ("alloc: %p", alloc)); |
| 632 | |||
| 633 |
6/6✓ Branch 0 taken 12182904 times.
✓ Branch 1 taken 39104 times.
✓ Branch 2 taken 12182903 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 12182897 times.
✓ Branch 5 taken 6 times.
|
12222008 | if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create) { |
| 634 |
2/4✓ Branch 0 taken 12182904 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12182904 times.
✗ Branch 3 not taken.
|
12182897 | if ((file = db_type->create(db_type, share, partitioned, alloc))) |
| 635 |
1/2✓ Branch 0 taken 12182900 times.
✗ Branch 1 not taken.
|
12182904 | file->init(); |
| 636 | 12182900 | return file; | |
| 637 | } | ||
| 638 | /* | ||
| 639 | Try the default table type | ||
| 640 | Here the call to current_thd() is ok as we call this function a lot of | ||
| 641 | times but we enter this branch very seldom. | ||
| 642 | */ | ||
| 643 |
1/2✓ Branch 0 taken 39104 times.
✗ Branch 1 not taken.
|
39104 | return get_new_handler(share, partitioned, alloc, |
| 644 |
2/4✓ Branch 0 taken 39104 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39104 times.
✗ Branch 3 not taken.
|
78215 | ha_default_handlerton(current_thd)); |
| 645 | 12222004 | } | |
| 646 | |||
| 647 | static const char **handler_errmsgs; | ||
| 648 | |||
| 649 | 25 | static const char *get_handler_errmsg(int nr) { | |
| 650 | 25 | return handler_errmsgs[nr - HA_ERR_FIRST]; | |
| 651 | } | ||
| 652 | |||
| 653 | /** | ||
| 654 | Register handler error messages for use with my_error(). | ||
| 655 | |||
| 656 | @retval | ||
| 657 | 0 OK | ||
| 658 | @retval | ||
| 659 | !=0 Error | ||
| 660 | */ | ||
| 661 | |||
| 662 | 9752 | int ha_init_errors(void) { | |
| 663 | #define SETMSG(nr, msg) handler_errmsgs[(nr)-HA_ERR_FIRST] = (msg) | ||
| 664 | |||
| 665 | /* Allocate a pointer array for the error message strings. */ | ||
| 666 | /* Zerofill it to avoid uninitialized gaps. */ | ||
| 667 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9752 times.
|
9752 | if (!(handler_errmsgs = static_cast<const char **>(my_malloc( |
| 668 | key_memory_errmsgs_handler, HA_ERR_ERRORS * sizeof(char *), | ||
| 669 | MYF(MY_WME | MY_ZEROFILL))))) | ||
| 670 | ✗ | return 1; | |
| 671 | |||
| 672 | /* Set the dedicated error messages. */ | ||
| 673 | 9752 | SETMSG(HA_ERR_KEY_NOT_FOUND, ER_DEFAULT(ER_KEY_NOT_FOUND)); | |
| 674 | 9752 | SETMSG(HA_ERR_FOUND_DUPP_KEY, ER_DEFAULT(ER_DUP_KEY)); | |
| 675 | 9752 | SETMSG(HA_ERR_RECORD_CHANGED, "Update wich is recoverable"); | |
| 676 | 9752 | SETMSG(HA_ERR_WRONG_INDEX, "Wrong index given to function"); | |
| 677 | 9752 | SETMSG(HA_ERR_CRASHED, ER_DEFAULT(ER_NOT_KEYFILE)); | |
| 678 | 9752 | SETMSG(HA_ERR_WRONG_IN_RECORD, ER_DEFAULT(ER_CRASHED_ON_USAGE)); | |
| 679 | 9752 | SETMSG(HA_ERR_OUT_OF_MEM, "Table handler out of memory"); | |
| 680 | 9752 | SETMSG(HA_ERR_NOT_A_TABLE, "Incorrect file format '%.64s'"); | |
| 681 | 9752 | SETMSG(HA_ERR_WRONG_COMMAND, "Command not supported"); | |
| 682 | 9752 | SETMSG(HA_ERR_OLD_FILE, ER_DEFAULT(ER_OLD_KEYFILE)); | |
| 683 | 9752 | SETMSG(HA_ERR_NO_ACTIVE_RECORD, "No record read in update"); | |
| 684 | 9752 | SETMSG(HA_ERR_RECORD_DELETED, "Intern record deleted"); | |
| 685 | 9752 | SETMSG(HA_ERR_RECORD_FILE_FULL, ER_DEFAULT(ER_RECORD_FILE_FULL)); | |
| 686 | 9752 | SETMSG(HA_ERR_INDEX_FILE_FULL, "No more room in index file '%.64s'"); | |
| 687 | 9752 | SETMSG(HA_ERR_END_OF_FILE, "End in next/prev/first/last"); | |
| 688 | 9752 | SETMSG(HA_ERR_UNSUPPORTED, ER_DEFAULT(ER_ILLEGAL_HA)); | |
| 689 | 9752 | SETMSG(HA_ERR_TOO_BIG_ROW, "Too big row"); | |
| 690 | 9752 | SETMSG(HA_WRONG_CREATE_OPTION, "Wrong create option"); | |
| 691 | 9752 | SETMSG(HA_ERR_FOUND_DUPP_UNIQUE, ER_DEFAULT(ER_DUP_UNIQUE)); | |
| 692 | 9752 | SETMSG(HA_ERR_UNKNOWN_CHARSET, "Can't open charset"); | |
| 693 | 9752 | SETMSG(HA_ERR_WRONG_MRG_TABLE_DEF, ER_DEFAULT(ER_WRONG_MRG_TABLE)); | |
| 694 | 9752 | SETMSG(HA_ERR_CRASHED_ON_REPAIR, ER_DEFAULT(ER_CRASHED_ON_REPAIR)); | |
| 695 | 9752 | SETMSG(HA_ERR_CRASHED_ON_USAGE, ER_DEFAULT(ER_CRASHED_ON_USAGE)); | |
| 696 | 9752 | SETMSG(HA_ERR_LOCK_WAIT_TIMEOUT, ER_DEFAULT(ER_LOCK_WAIT_TIMEOUT)); | |
| 697 | 9752 | SETMSG(HA_ERR_LOCK_TABLE_FULL, ER_DEFAULT(ER_LOCK_TABLE_FULL)); | |
| 698 | 9752 | SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER_DEFAULT(ER_READ_ONLY_TRANSACTION)); | |
| 699 | 9752 | SETMSG(HA_ERR_LOCK_DEADLOCK, ER_DEFAULT(ER_LOCK_DEADLOCK)); | |
| 700 | 9752 | SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER_DEFAULT(ER_CANNOT_ADD_FOREIGN)); | |
| 701 | 9752 | SETMSG(HA_ERR_NO_REFERENCED_ROW, ER_DEFAULT(ER_NO_REFERENCED_ROW_2)); | |
| 702 | 9752 | SETMSG(HA_ERR_ROW_IS_REFERENCED, ER_DEFAULT(ER_ROW_IS_REFERENCED_2)); | |
| 703 | 9752 | SETMSG(HA_ERR_NO_SAVEPOINT, "No savepoint with that name"); | |
| 704 | 9752 | SETMSG(HA_ERR_NON_UNIQUE_BLOCK_SIZE, "Non unique key block size"); | |
| 705 | 9752 | SETMSG(HA_ERR_NO_SUCH_TABLE, "No such table: '%.64s'"); | |
| 706 | 9752 | SETMSG(HA_ERR_TABLE_EXIST, ER_DEFAULT(ER_TABLE_EXISTS_ERROR)); | |
| 707 | 9752 | SETMSG(HA_ERR_NO_CONNECTION, "Could not connect to storage engine"); | |
| 708 | 9752 | SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER_DEFAULT(ER_TABLE_DEF_CHANGED)); | |
| 709 | 9752 | SETMSG(HA_ERR_FOREIGN_DUPLICATE_KEY, | |
| 710 | "FK constraint would lead to duplicate key"); | ||
| 711 | 9752 | SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, ER_DEFAULT(ER_TABLE_NEEDS_UPGRADE)); | |
| 712 | 9752 | SETMSG(HA_ERR_TABLE_READONLY, ER_DEFAULT(ER_OPEN_AS_READONLY)); | |
| 713 | 9752 | SETMSG(HA_ERR_AUTOINC_READ_FAILED, ER_DEFAULT(ER_AUTOINC_READ_FAILED)); | |
| 714 | 9752 | SETMSG(HA_ERR_AUTOINC_ERANGE, ER_DEFAULT(ER_WARN_DATA_OUT_OF_RANGE)); | |
| 715 | 9752 | SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, | |
| 716 | ER_DEFAULT(ER_TOO_MANY_CONCURRENT_TRXS)); | ||
| 717 | 9752 | SETMSG(HA_ERR_INDEX_COL_TOO_LONG, ER_DEFAULT(ER_INDEX_COLUMN_TOO_LONG)); | |
| 718 | 9752 | SETMSG(HA_ERR_INDEX_CORRUPT, ER_DEFAULT(ER_INDEX_CORRUPT)); | |
| 719 | 9752 | SETMSG(HA_FTS_INVALID_DOCID, "Invalid InnoDB FTS Doc ID"); | |
| 720 | 9752 | SETMSG(HA_ERR_TABLE_IN_FK_CHECK, ER_DEFAULT(ER_TABLE_IN_FK_CHECK)); | |
| 721 | 9752 | SETMSG(HA_ERR_TABLESPACE_EXISTS, "Tablespace already exists"); | |
| 722 | 9752 | SETMSG(HA_ERR_TABLESPACE_MISSING, ER_DEFAULT(ER_TABLESPACE_MISSING)); | |
| 723 | 9752 | SETMSG(HA_ERR_FTS_EXCEED_RESULT_CACHE_LIMIT, | |
| 724 | "FTS query exceeds result cache limit"); | ||
| 725 | 9752 | SETMSG(HA_ERR_TEMP_FILE_WRITE_FAILURE, | |
| 726 | ER_DEFAULT(ER_TEMP_FILE_WRITE_FAILURE)); | ||
| 727 | 9752 | SETMSG(HA_ERR_INNODB_FORCED_RECOVERY, ER_DEFAULT(ER_INNODB_FORCED_RECOVERY)); | |
| 728 | 9752 | SETMSG(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE, | |
| 729 | "Too many words in a FTS phrase or proximity search"); | ||
| 730 | 9752 | SETMSG(HA_ERR_TABLE_CORRUPT, ER_DEFAULT(ER_TABLE_CORRUPT)); | |
| 731 | 9752 | SETMSG(HA_ERR_TABLESPACE_MISSING, ER_DEFAULT(ER_TABLESPACE_MISSING)); | |
| 732 | 9752 | SETMSG(HA_ERR_TABLESPACE_IS_NOT_EMPTY, | |
| 733 | ER_DEFAULT(ER_TABLESPACE_IS_NOT_EMPTY)); | ||
| 734 | 9752 | SETMSG(HA_ERR_WRONG_FILE_NAME, ER_DEFAULT(ER_WRONG_FILE_NAME)); | |
| 735 | 9752 | SETMSG(HA_ERR_NOT_ALLOWED_COMMAND, ER_DEFAULT(ER_NOT_ALLOWED_COMMAND)); | |
| 736 | 9752 | SETMSG(HA_ERR_COMPUTE_FAILED, "Compute virtual column value failed"); | |
| 737 | 9752 | SETMSG(HA_ERR_DISK_FULL_NOWAIT, ER_DEFAULT(ER_DISK_FULL_NOWAIT)); | |
| 738 | 9752 | SETMSG(HA_ERR_NO_SESSION_TEMP, ER_DEFAULT(ER_NO_SESSION_TEMP)); | |
| 739 | 9752 | SETMSG(HA_ERR_WRONG_TABLE_NAME, ER_DEFAULT(ER_WRONG_TABLE_NAME)); | |
| 740 | 9752 | SETMSG(HA_ERR_TOO_LONG_PATH, ER_DEFAULT(ER_TABLE_NAME_CAUSES_TOO_LONG_PATH)); | |
| 741 | 9752 | SETMSG(HA_ERR_FTS_TOO_MANY_NESTED_EXP, | |
| 742 | "Too many nested sub-expressions in a full-text search"); | ||
| 743 | /* Register the error messages for use with my_error(). */ | ||
| 744 | 9752 | return my_error_register(get_handler_errmsg, HA_ERR_FIRST, HA_ERR_LAST); | |
| 745 | } | ||
| 746 | |||
| 747 | 91220 | int ha_finalize_handlerton(st_plugin_int *plugin) { | |
| 748 | 91220 | handlerton *hton = (handlerton *)plugin->data; | |
| 749 |
1/2✓ Branch 0 taken 91220 times.
✗ Branch 1 not taken.
|
91220 | DBUG_TRACE; |
| 750 | |||
| 751 | /* hton can be NULL here, if ha_initialize_handlerton() failed. */ | ||
| 752 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91220 times.
|
91220 | if (!hton) goto end; |
| 753 | |||
| 754 |
2/3✓ Branch 0 taken 143 times.
✓ Branch 1 taken 91077 times.
✗ Branch 2 not taken.
|
91220 | switch (hton->state) { |
| 755 | 143 | case SHOW_OPTION_NO: | |
| 756 | case SHOW_OPTION_DISABLED: | ||
| 757 | 143 | break; | |
| 758 | 91077 | case SHOW_OPTION_YES: | |
| 759 |
1/2✓ Branch 0 taken 91077 times.
✗ Branch 1 not taken.
|
91077 | if (installed_htons[hton->db_type] == hton) |
| 760 | 91077 | installed_htons[hton->db_type] = nullptr; | |
| 761 | 91077 | break; | |
| 762 | }; | ||
| 763 | |||
| 764 |
3/4✓ Branch 0 taken 33244 times.
✓ Branch 1 taken 57976 times.
✓ Branch 2 taken 33244 times.
✗ Branch 3 not taken.
|
91220 | if (hton->panic) hton->panic(hton, HA_PANIC_CLOSE); |
| 765 | |||
| 766 |
2/2✓ Branch 0 taken 58174 times.
✓ Branch 1 taken 33046 times.
|
91220 | if (plugin->plugin->deinit) { |
| 767 | /* | ||
| 768 | Today we have no defined/special behavior for uninstalling | ||
| 769 | engine plugins. | ||
| 770 | */ | ||
| 771 |
3/8✓ Branch 0 taken 58174 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 58174 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 58174 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
58174 | DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str)); |
| 772 |
2/4✓ Branch 0 taken 58174 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 58174 times.
|
58174 | if (plugin->plugin->deinit(nullptr)) { |
| 773 | ✗ | DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.", | |
| 774 | plugin->name.str)); | ||
| 775 | } | ||
| 776 | } | ||
| 777 | |||
| 778 | /* | ||
| 779 | In case a plugin is uninstalled and re-installed later, it should | ||
| 780 | reuse an array slot. Otherwise the number of uninstall/install | ||
| 781 | cycles would be limited. | ||
| 782 | */ | ||
| 783 |
2/2✓ Branch 0 taken 91077 times.
✓ Branch 1 taken 143 times.
|
91220 | if (hton->slot != HA_SLOT_UNDEF) { |
| 784 | /* Make sure we are not unpluging another plugin */ | ||
| 785 |
2/4✓ Branch 0 taken 91077 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 91077 times.
|
91077 | assert(se_plugin_array[hton->slot] == plugin); |
| 786 |
2/4✓ Branch 0 taken 91077 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 91077 times.
|
91077 | assert(hton->slot < se_plugin_array.size()); |
| 787 |
1/2✓ Branch 0 taken 91077 times.
✗ Branch 1 not taken.
|
91077 | se_plugin_array[hton->slot] = NULL; |
| 788 |
1/2✓ Branch 0 taken 91077 times.
✗ Branch 1 not taken.
|
91077 | builtin_htons[hton->slot] = false; /* Extra correctness. */ |
| 789 | } | ||
| 790 | |||
| 791 |
1/2✓ Branch 0 taken 91220 times.
✗ Branch 1 not taken.
|
91220 | my_free(hton); |
| 792 | 91220 | plugin->data = nullptr; | |
| 793 | 91220 | end: | |
| 794 | 91220 | return 0; | |
| 795 | 91220 | } | |
| 796 | |||
| 797 | 106137 | int ha_initialize_handlerton(st_plugin_int *plugin) { | |
| 798 | handlerton *hton; | ||
| 799 |
1/2✓ Branch 0 taken 106137 times.
✗ Branch 1 not taken.
|
106137 | DBUG_TRACE; |
| 800 |
3/8✓ Branch 0 taken 106137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 106137 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 106137 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
106137 | DBUG_PRINT("plugin", ("initialize plugin: '%s'", plugin->name.str)); |
| 801 | |||
| 802 |
1/2✓ Branch 0 taken 106137 times.
✗ Branch 1 not taken.
|
106137 | hton = static_cast<handlerton *>(my_malloc(key_memory_handlerton_objects, |
| 803 | sizeof(handlerton), | ||
| 804 | MYF(MY_WME | MY_ZEROFILL))); | ||
| 805 | |||
| 806 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 106137 times.
|
106137 | if (hton == nullptr) { |
| 807 | ✗ | LogErr(ERROR_LEVEL, ER_HANDLERTON_OOM, plugin->name.str); | |
| 808 | ✗ | goto err_no_hton_memory; | |
| 809 | } | ||
| 810 | |||
| 811 | 106137 | hton->slot = HA_SLOT_UNDEF; | |
| 812 | /* Historical Requirement */ | ||
| 813 | 106137 | plugin->data = hton; // shortcut for the future | |
| 814 |
6/8✓ Branch 0 taken 106137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 106137 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 106120 times.
✓ Branch 6 taken 17 times.
✓ Branch 7 taken 106120 times.
|
106137 | if (plugin->plugin->init && plugin->plugin->init(hton)) { |
| 815 |
8/16✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 17 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 17 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 17 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 17 times.
✗ Branch 15 not taken.
|
17 | LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); |
| 816 | 17 | goto err; | |
| 817 | } | ||
| 818 | |||
| 819 | /* | ||
| 820 | the switch below and hton->state should be removed when | ||
| 821 | command-line options for plugins will be implemented | ||
| 822 | */ | ||
| 823 |
3/8✓ Branch 0 taken 106120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 106120 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 106120 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
106120 | DBUG_PRINT("info", ("hton->state=%d", hton->state)); |
| 824 |
2/3✓ Branch 0 taken 252 times.
✓ Branch 1 taken 105868 times.
✗ Branch 2 not taken.
|
106120 | switch (hton->state) { |
| 825 | 252 | case SHOW_OPTION_NO: | |
| 826 | 252 | break; | |
| 827 | 105868 | case SHOW_OPTION_YES: { | |
| 828 | uint tmp; | ||
| 829 | ulong fslot; | ||
| 830 | /* now check the db_type for conflict */ | ||
| 831 |
2/2✓ Branch 0 taken 96200 times.
✓ Branch 1 taken 9668 times.
|
105868 | if (hton->db_type <= DB_TYPE_UNKNOWN || |
| 832 |
2/4✓ Branch 0 taken 96200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 96200 times.
|
96200 | hton->db_type >= DB_TYPE_DEFAULT || installed_htons[hton->db_type]) { |
| 833 | 9668 | int idx = (int)DB_TYPE_FIRST_DYNAMIC; | |
| 834 | |||
| 835 |
3/4✓ Branch 0 taken 9730 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 9668 times.
|
9730 | while (idx < (int)DB_TYPE_DEFAULT && installed_htons[idx]) idx++; |
| 836 | |||
| 837 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9668 times.
|
9668 | if (idx == (int)DB_TYPE_DEFAULT) { |
| 838 | ✗ | LogErr(WARNING_LEVEL, ER_TOO_MANY_STORAGE_ENGINES); | |
| 839 | ✗ | goto err_deinit; | |
| 840 | } | ||
| 841 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9668 times.
|
9668 | if (hton->db_type != DB_TYPE_UNKNOWN) |
| 842 | ✗ | LogErr(WARNING_LEVEL, ER_SE_TYPECODE_CONFLICT, plugin->plugin->name, | |
| 843 | idx); | ||
| 844 | 9668 | hton->db_type = (enum legacy_db_type)idx; | |
| 845 | } | ||
| 846 | |||
| 847 | /* | ||
| 848 | In case a plugin is uninstalled and re-installed later, it should | ||
| 849 | reuse an array slot. Otherwise the number of uninstall/install | ||
| 850 | cycles would be limited. So look for a free slot. | ||
| 851 | */ | ||
| 852 |
3/10✓ Branch 0 taken 105868 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 105868 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 105868 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
105868 | DBUG_PRINT("plugin", |
| 853 | ("total_ha: %lu", static_cast<ulong>(se_plugin_array.size()))); | ||
| 854 |
3/4✓ Branch 0 taken 632778 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 526939 times.
✓ Branch 3 taken 105839 times.
|
632778 | for (fslot = 0; fslot < se_plugin_array.size(); fslot++) { |
| 855 |
3/4✓ Branch 0 taken 526939 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 526910 times.
|
526939 | if (!se_plugin_array[fslot]) break; |
| 856 | } | ||
| 857 |
3/4✓ Branch 0 taken 105868 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 105839 times.
|
105868 | if (fslot < se_plugin_array.size()) |
| 858 | 29 | hton->slot = fslot; | |
| 859 | else { | ||
| 860 |
1/2✓ Branch 0 taken 105839 times.
✗ Branch 1 not taken.
|
105839 | hton->slot = se_plugin_array.size(); |
| 861 | } | ||
| 862 |
2/4✓ Branch 0 taken 105868 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 105868 times.
✗ Branch 3 not taken.
|
211736 | if (se_plugin_array.assign_at(hton->slot, plugin) || |
| 863 |
3/6✓ Branch 0 taken 105868 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 105868 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 105868 times.
|
211736 | builtin_htons.assign_at(hton->slot, (plugin->plugin_dl == nullptr))) |
| 864 | ✗ | goto err_deinit; | |
| 865 | |||
| 866 | 105868 | installed_htons[hton->db_type] = hton; | |
| 867 | 105868 | tmp = hton->savepoint_offset; | |
| 868 | 105868 | hton->savepoint_offset = savepoint_alloc_size; | |
| 869 | 105868 | savepoint_alloc_size += tmp; | |
| 870 |
2/2✓ Branch 0 taken 19071 times.
✓ Branch 1 taken 86797 times.
|
105868 | if (hton->prepare) total_ha_2pc++; |
| 871 | 105868 | break; | |
| 872 | } | ||
| 873 | [[fallthrough]]; | ||
| 874 | ✗ | default: | |
| 875 | ✗ | hton->state = SHOW_OPTION_DISABLED; | |
| 876 | ✗ | break; | |
| 877 | } | ||
| 878 | |||
| 879 | /* | ||
| 880 | This is entirely for legacy. We will create a new "disk based" hton and a | ||
| 881 | "memory" hton which will be configurable longterm. We should be able to | ||
| 882 | remove partition and myisammrg. | ||
| 883 | */ | ||
| 884 |
5/5✓ Branch 0 taken 9606 times.
✓ Branch 1 taken 9606 times.
✓ Branch 2 taken 9735 times.
✓ Branch 3 taken 9717 times.
✓ Branch 4 taken 67456 times.
|
106120 | switch (hton->db_type) { |
| 885 | 9606 | case DB_TYPE_HEAP: | |
| 886 | 9606 | heap_hton = hton; | |
| 887 | 9606 | break; | |
| 888 | 9606 | case DB_TYPE_TEMPTABLE: | |
| 889 | 9606 | temptable_hton = hton; | |
| 890 | 9606 | break; | |
| 891 | 9735 | case DB_TYPE_MYISAM: | |
| 892 | 9735 | myisam_hton = hton; | |
| 893 | 9735 | break; | |
| 894 | 9717 | case DB_TYPE_INNODB: | |
| 895 | 9717 | innodb_hton = hton; | |
| 896 | 9717 | break; | |
| 897 | 67456 | default: | |
| 898 | 67456 | break; | |
| 899 | }; | ||
| 900 | |||
| 901 | /* | ||
| 902 | Re-load the optimizer cost constants since this storage engine can | ||
| 903 | have non-default cost constants. | ||
| 904 | */ | ||
| 905 |
1/2✓ Branch 0 taken 106120 times.
✗ Branch 1 not taken.
|
106120 | reload_optimizer_cost_constants(); |
| 906 | |||
| 907 | 106120 | return 0; | |
| 908 | |||
| 909 | ✗ | err_deinit: | |
| 910 | /* | ||
| 911 | Let plugin do its inner deinitialization as plugin->init() | ||
| 912 | was successfully called before. | ||
| 913 | */ | ||
| 914 | ✗ | if (plugin->plugin->deinit) (void)plugin->plugin->deinit(nullptr); | |
| 915 | |||
| 916 | ✗ | err: | |
| 917 |
1/2✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
|
17 | my_free(hton); |
| 918 | 17 | err_no_hton_memory: | |
| 919 | 17 | plugin->data = nullptr; | |
| 920 | 17 | return 1; | |
| 921 | 106137 | } | |
| 922 | |||
| 923 | 9575 | int ha_init() { | |
| 924 | 9575 | int error = 0; | |
| 925 |
1/2✓ Branch 0 taken 9575 times.
✗ Branch 1 not taken.
|
9575 | DBUG_TRACE; |
| 926 | |||
| 927 | /* | ||
| 928 | Check if there is a transaction-capable storage engine besides the | ||
| 929 | binary log. | ||
| 930 | */ | ||
| 931 | 9575 | opt_using_transactions = | |
| 932 |
1/2✓ Branch 0 taken 9575 times.
✗ Branch 1 not taken.
|
9575 | se_plugin_array.size() > static_cast<ulong>(opt_bin_log); |
| 933 | 9575 | savepoint_alloc_size += sizeof(SAVEPOINT); | |
| 934 | |||
| 935 | 9575 | return error; | |
| 936 | 9575 | } | |
| 937 | |||
| 938 | 8457 | void ha_end() { | |
| 939 | // Unregister handler error messages. | ||
| 940 | 8457 | my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST); | |
| 941 | 8457 | my_free(handler_errmsgs); | |
| 942 | 8457 | } | |
| 943 | |||
| 944 | 54833 | static bool dropdb_handlerton(THD *, plugin_ref plugin, void *path) { | |
| 945 | 54833 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 946 |
3/4✓ Branch 0 taken 54810 times.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54810 times.
|
54833 | if (hton->state == SHOW_OPTION_YES && hton->drop_database) |
| 947 | ✗ | hton->drop_database(hton, (char *)path); | |
| 948 | 54833 | return false; | |
| 949 | } | ||
| 950 | |||
| 951 | 5053 | void ha_drop_database(char *path) { | |
| 952 | 5053 | plugin_foreach(nullptr, dropdb_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, path); | |
| 953 | 5053 | } | |
| 954 | |||
| 955 | 145933751 | static bool closecon_handlerton(THD *thd, plugin_ref plugin, void *) { | |
| 956 | 145933751 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 957 | /* | ||
| 958 | there's no need to rollback here as all transactions must | ||
| 959 | be rolled back already | ||
| 960 | */ | ||
| 961 |
6/6✓ Branch 0 taken 145682609 times.
✓ Branch 1 taken 251155 times.
✓ Branch 2 taken 15805875 times.
✓ Branch 3 taken 129877238 times.
✓ Branch 4 taken 15805874 times.
✓ Branch 5 taken 130128394 times.
|
145933764 | if (hton->state == SHOW_OPTION_YES && thd_get_ha_data(thd, hton)) { |
| 962 |
2/2✓ Branch 0 taken 15805873 times.
✓ Branch 1 taken 1 times.
|
15805874 | if (hton->close_connection) hton->close_connection(hton, thd); |
| 963 | /* make sure ha_data is reset and ha_data_lock is released */ | ||
| 964 | 15805876 | thd_set_ha_data(thd, hton, nullptr); | |
| 965 | } | ||
| 966 | 145934028 | return false; | |
| 967 | } | ||
| 968 | |||
| 969 | /** | ||
| 970 | @note | ||
| 971 | don't bother to rollback here, it's done already | ||
| 972 | */ | ||
| 973 | 16360988 | void ha_close_connection(THD *thd) { | |
| 974 | 16360988 | plugin_foreach(thd, closecon_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, | |
| 975 | nullptr); | ||
| 976 | 16362194 | } | |
| 977 | |||
| 978 | 171311 | static bool kill_handlerton(THD *thd, plugin_ref plugin, void *) { | |
| 979 | 171311 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 980 | |||
| 981 |
4/4✓ Branch 0 taken 171091 times.
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 15572 times.
✓ Branch 3 taken 155519 times.
|
171311 | if (hton->state == SHOW_OPTION_YES && hton->kill_connection) { |
| 982 |
2/2✓ Branch 0 taken 1431 times.
✓ Branch 1 taken 14141 times.
|
15572 | if (thd_get_ha_data(thd, hton)) hton->kill_connection(hton, thd); |
| 983 | } | ||
| 984 | |||
| 985 | 171311 | return false; | |
| 986 | } | ||
| 987 | |||
| 988 | 16040 | void ha_kill_connection(THD *thd) { | |
| 989 | #ifdef WITH_WSREP | ||
| 990 |
2/2✓ Branch 0 taken 467 times.
✓ Branch 1 taken 15573 times.
|
16040 | if (thd->wsrep_aborter) |
| 991 | { | ||
| 992 |
1/20✗ Branch 0 not taken.
✓ Branch 1 taken 467 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
467 | WSREP_DEBUG("thd is already aborted in innodb: %u", thd->wsrep_aborter); |
| 993 | 467 | return; | |
| 994 | } | ||
| 995 | #endif /* WITH_WSREP */ | ||
| 996 | 15573 | plugin_foreach(thd, kill_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, nullptr); | |
| 997 | } | ||
| 998 | |||
| 999 | /** Invoke handlerton::pre_dd_shutdown() on a plugin. | ||
| 1000 | @param plugin storage engine plugin | ||
| 1001 | @retval false (always) */ | ||
| 1002 | 91211 | static bool pre_dd_shutdown_handlerton(THD *, plugin_ref plugin, void *) { | |
| 1003 | 91211 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 1004 |
4/4✓ Branch 0 taken 91068 times.
✓ Branch 1 taken 143 times.
✓ Branch 2 taken 8375 times.
✓ Branch 3 taken 82693 times.
|
91211 | if (hton->state == SHOW_OPTION_YES && hton->pre_dd_shutdown) |
| 1005 | 8375 | hton->pre_dd_shutdown(hton); | |
| 1006 | 91197 | return false; | |
| 1007 | } | ||
| 1008 | |||
| 1009 | /** Invoke handlerton::pre_dd_shutdown() on every storage engine plugin. */ | ||
| 1010 | 8471 | void ha_pre_dd_shutdown(void) { | |
| 1011 | 8471 | plugin_foreach(nullptr, pre_dd_shutdown_handlerton, | |
| 1012 | MYSQL_STORAGE_ENGINE_PLUGIN, nullptr); | ||
| 1013 | 8457 | } | |
| 1014 | |||
| 1015 | /* ======================================================================== | ||
| 1016 | ======================= TRANSACTIONS ===================================*/ | ||
| 1017 | |||
| 1018 | /** | ||
| 1019 | Transaction handling in the server | ||
| 1020 | ================================== | ||
| 1021 | |||
| 1022 | In each client connection, MySQL maintains two transactional | ||
| 1023 | states: | ||
| 1024 | - a statement transaction, | ||
| 1025 | - a standard, also called normal transaction. | ||
| 1026 | |||
| 1027 | Historical note | ||
| 1028 | --------------- | ||
| 1029 | "Statement transaction" is a non-standard term that comes | ||
| 1030 | from the times when MySQL supported BerkeleyDB storage engine. | ||
| 1031 | |||
| 1032 | First of all, it should be said that in BerkeleyDB auto-commit | ||
| 1033 | mode auto-commits operations that are atomic to the storage | ||
| 1034 | engine itself, such as a write of a record, and are too | ||
| 1035 | high-granular to be atomic from the application perspective | ||
| 1036 | (MySQL). One SQL statement could involve many BerkeleyDB | ||
| 1037 | auto-committed operations and thus BerkeleyDB auto-commit was of | ||
| 1038 | little use to MySQL. | ||
| 1039 | |||
| 1040 | Secondly, instead of SQL standard savepoints, BerkeleyDB | ||
| 1041 | provided the concept of "nested transactions". In a nutshell, | ||
| 1042 | transactions could be arbitrarily nested, but when the parent | ||
| 1043 | transaction was committed or aborted, all its child (nested) | ||
| 1044 | transactions were handled committed or aborted as well. | ||
| 1045 | Commit of a nested transaction, in turn, made its changes | ||
| 1046 | visible, but not durable: it destroyed the nested transaction, | ||
| 1047 | all its changes would become available to the parent and | ||
| 1048 | currently active nested transactions of this parent. | ||
| 1049 | |||
| 1050 | So the mechanism of nested transactions was employed to | ||
| 1051 | provide "all or nothing" guarantee of SQL statements | ||
| 1052 | required by the standard. | ||
| 1053 | A nested transaction would be created at start of each SQL | ||
| 1054 | statement, and destroyed (committed or aborted) at statement | ||
| 1055 | end. Such nested transaction was internally referred to as | ||
| 1056 | a "statement transaction" and gave birth to the term. | ||
| 1057 | |||
| 1058 | (Historical note ends) | ||
| 1059 | |||
| 1060 | Since then a statement transaction is started for each statement | ||
| 1061 | that accesses transactional tables or uses the binary log. If | ||
| 1062 | the statement succeeds, the statement transaction is committed. | ||
| 1063 | If the statement fails, the transaction is rolled back. Commits | ||
| 1064 | of statement transactions are not durable -- each such | ||
| 1065 | transaction is nested in the normal transaction, and if the | ||
| 1066 | normal transaction is rolled back, the effects of all enclosed | ||
| 1067 | statement transactions are undone as well. Technically, | ||
| 1068 | a statement transaction can be viewed as a savepoint which is | ||
| 1069 | maintained automatically in order to make effects of one | ||
| 1070 | statement atomic. | ||
| 1071 | |||
| 1072 | The normal transaction is started by the user and is ended | ||
| 1073 | usually upon a user request as well. The normal transaction | ||
| 1074 | encloses transactions of all statements issued between | ||
| 1075 | its beginning and its end. | ||
| 1076 | In autocommit mode, the normal transaction is equivalent | ||
| 1077 | to the statement transaction. | ||
| 1078 | |||
| 1079 | Since MySQL supports PSEA (pluggable storage engine | ||
| 1080 | architecture), more than one transactional engine can be | ||
| 1081 | active at a time. Hence transactions, from the server | ||
| 1082 | point of view, are always distributed. In particular, | ||
| 1083 | transactional state is maintained independently for each | ||
| 1084 | engine. In order to commit a transaction the two phase | ||
| 1085 | commit protocol is employed. | ||
| 1086 | |||
| 1087 | Not all statements are executed in context of a transaction. | ||
| 1088 | Administrative and status information statements do not modify | ||
| 1089 | engine data, and thus do not start a statement transaction and | ||
| 1090 | also have no effect on the normal transaction. Examples of such | ||
| 1091 | statements are SHOW STATUS and RESET SLAVE. | ||
| 1092 | |||
| 1093 | Similarly DDL statements are not transactional, | ||
| 1094 | and therefore a transaction is [almost] never started for a DDL | ||
| 1095 | statement. The difference between a DDL statement and a purely | ||
| 1096 | administrative statement though is that a DDL statement always | ||
| 1097 | commits the current transaction before proceeding, if there is | ||
| 1098 | any. | ||
| 1099 | |||
| 1100 | At last, SQL statements that work with non-transactional | ||
| 1101 | engines also have no effect on the transaction state of the | ||
| 1102 | connection. Even though they are written to the binary log, | ||
| 1103 | and the binary log is, overall, transactional, the writes | ||
| 1104 | are done in "write-through" mode, directly to the binlog | ||
| 1105 | file, followed with a OS cache sync, in other words, | ||
| 1106 | bypassing the binlog undo log (translog). | ||
| 1107 | They do not commit the current normal transaction. | ||
| 1108 | A failure of a statement that uses non-transactional tables | ||
| 1109 | would cause a rollback of the statement transaction, but | ||
| 1110 | in case there no non-transactional tables are used, | ||
| 1111 | no statement transaction is started. | ||
| 1112 | |||
| 1113 | Data layout | ||
| 1114 | ----------- | ||
| 1115 | |||
| 1116 | The server stores its transaction-related data in | ||
| 1117 | thd->transaction. This structure has two members of type | ||
| 1118 | THD_TRANS. These members correspond to the statement and | ||
| 1119 | normal transactions respectively: | ||
| 1120 | |||
| 1121 | - thd->transaction.stmt contains a list of engines | ||
| 1122 | that are participating in the given statement | ||
| 1123 | - thd->transaction.all contains a list of engines that | ||
| 1124 | have participated in any of the statement transactions started | ||
| 1125 | within the context of the normal transaction. | ||
| 1126 | Each element of the list contains a pointer to the storage | ||
| 1127 | engine, engine-specific transactional data, and engine-specific | ||
| 1128 | transaction flags. | ||
| 1129 | |||
| 1130 | In autocommit mode thd->transaction.all is empty. | ||
| 1131 | Instead, data of thd->transaction.stmt is | ||
| 1132 | used to commit/rollback the normal transaction. | ||
| 1133 | |||
| 1134 | The list of registered engines has a few important properties: | ||
| 1135 | - no engine is registered in the list twice | ||
| 1136 | - engines are present in the list a reverse temporal order -- | ||
| 1137 | new participants are always added to the beginning of the list. | ||
| 1138 | |||
| 1139 | Transaction life cycle | ||
| 1140 | ---------------------- | ||
| 1141 | |||
| 1142 | When a new connection is established, thd->transaction | ||
| 1143 | members are initialized to an empty state. | ||
| 1144 | If a statement uses any tables, all affected engines | ||
| 1145 | are registered in the statement engine list. In | ||
| 1146 | non-autocommit mode, the same engines are registered in | ||
| 1147 | the normal transaction list. | ||
| 1148 | At the end of the statement, the server issues a commit | ||
| 1149 | or a roll back for all engines in the statement list. | ||
| 1150 | At this point transaction flags of an engine, if any, are | ||
| 1151 | propagated from the statement list to the list of the normal | ||
| 1152 | transaction. | ||
| 1153 | When commit/rollback is finished, the statement list is | ||
| 1154 | cleared. It will be filled in again by the next statement, | ||
| 1155 | and emptied again at the next statement's end. | ||
| 1156 | |||
| 1157 | The normal transaction is committed in a similar way | ||
| 1158 | (by going over all engines in thd->transaction.all list) | ||
| 1159 | but at different times: | ||
| 1160 | - upon COMMIT SQL statement is issued by the user | ||
| 1161 | - implicitly, by the server, at the beginning of a DDL statement | ||
| 1162 | or SET AUTOCOMMIT={0|1} statement. | ||
| 1163 | |||
| 1164 | The normal transaction can be rolled back as well: | ||
| 1165 | - if the user has requested so, by issuing ROLLBACK SQL | ||
| 1166 | statement | ||
| 1167 | - if one of the storage engines requested a rollback | ||
| 1168 | by setting thd->transaction_rollback_request. This may | ||
| 1169 | happen in case, e.g., when the transaction in the engine was | ||
| 1170 | chosen a victim of the internal deadlock resolution algorithm | ||
| 1171 | and rolled back internally. When such a situation happens, there | ||
| 1172 | is little the server can do and the only option is to rollback | ||
| 1173 | transactions in all other participating engines. In this case | ||
| 1174 | the rollback is accompanied by an error sent to the user. | ||
| 1175 | |||
| 1176 | As follows from the use cases above, the normal transaction | ||
| 1177 | is never committed when there is an outstanding statement | ||
| 1178 | transaction. In most cases there is no conflict, since | ||
| 1179 | commits of the normal transaction are issued by a stand-alone | ||
| 1180 | administrative or DDL statement, thus no outstanding statement | ||
| 1181 | transaction of the previous statement exists. Besides, | ||
| 1182 | all statements that manipulate with the normal transaction | ||
| 1183 | are prohibited in stored functions and triggers, therefore | ||
| 1184 | no conflicting situation can occur in a sub-statement either. | ||
| 1185 | The remaining rare cases when the server explicitly has | ||
| 1186 | to commit the statement transaction prior to committing the normal | ||
| 1187 | one cover error-handling scenarios (see for example | ||
| 1188 | SQLCOM_LOCK_TABLES). | ||
| 1189 | |||
| 1190 | When committing a statement or a normal transaction, the server | ||
| 1191 | either uses the two-phase commit protocol, or issues a commit | ||
| 1192 | in each engine independently. The two-phase commit protocol | ||
| 1193 | is used only if: | ||
| 1194 | - all participating engines support two-phase commit (provide | ||
| 1195 | handlerton::prepare PSEA API call) and | ||
| 1196 | - transactions in at least two engines modify data (i.e. are | ||
| 1197 | not read-only). | ||
| 1198 | |||
| 1199 | Note that the two phase commit is used for | ||
| 1200 | statement transactions, even though they are not durable anyway. | ||
| 1201 | This is done to ensure logical consistency of data in a multiple- | ||
| 1202 | engine transaction. | ||
| 1203 | For example, imagine that some day MySQL supports unique | ||
| 1204 | constraint checks deferred till the end of statement. In such | ||
| 1205 | case a commit in one of the engines may yield ER_DUP_KEY, | ||
| 1206 | and MySQL should be able to gracefully abort statement | ||
| 1207 | transactions of other participants. | ||
| 1208 | |||
| 1209 | After the normal transaction has been committed, | ||
| 1210 | thd->transaction.all list is cleared. | ||
| 1211 | |||
| 1212 | When a connection is closed, the current normal transaction, if | ||
| 1213 | any, is rolled back. | ||
| 1214 | |||
| 1215 | Roles and responsibilities | ||
| 1216 | -------------------------- | ||
| 1217 | |||
| 1218 | The server has no way to know that an engine participates in | ||
| 1219 | the statement and a transaction has been started | ||
| 1220 | in it unless the engine says so. Thus, in order to be | ||
| 1221 | a part of a transaction, the engine must "register" itself. | ||
| 1222 | This is done by invoking trans_register_ha() server call. | ||
| 1223 | Normally the engine registers itself whenever handler::external_lock() | ||
| 1224 | is called. trans_register_ha() can be invoked many times: if | ||
| 1225 | an engine is already registered, the call does nothing. | ||
| 1226 | In case autocommit is not set, the engine must register itself | ||
| 1227 | twice -- both in the statement list and in the normal transaction | ||
| 1228 | list. | ||
| 1229 | In which list to register is a parameter of trans_register_ha(). | ||
| 1230 | |||
| 1231 | Note, that although the registration interface in itself is | ||
| 1232 | fairly clear, the current usage practice often leads to undesired | ||
| 1233 | effects. E.g. since a call to trans_register_ha() in most engines | ||
| 1234 | is embedded into implementation of handler::external_lock(), some | ||
| 1235 | DDL statements start a transaction (at least from the server | ||
| 1236 | point of view) even though they are not expected to. E.g. | ||
| 1237 | CREATE TABLE does not start a transaction, since | ||
| 1238 | handler::external_lock() is never called during CREATE TABLE. But | ||
| 1239 | CREATE TABLE ... SELECT does, since handler::external_lock() is | ||
| 1240 | called for the table that is being selected from. This has no | ||
| 1241 | practical effects currently, but must be kept in mind | ||
| 1242 | nevertheless. | ||
| 1243 | |||
| 1244 | Once an engine is registered, the server will do the rest | ||
| 1245 | of the work. | ||
| 1246 | |||
| 1247 | During statement execution, whenever any of data-modifying | ||
| 1248 | PSEA API methods is used, e.g. handler::write_row() or | ||
| 1249 | handler::update_row(), the read-write flag is raised in the | ||
| 1250 | statement transaction for the involved engine. | ||
| 1251 | Currently All PSEA calls are "traced", and the data can not be | ||
| 1252 | changed in a way other than issuing a PSEA call. Important: | ||
| 1253 | unless this invariant is preserved the server will not know that | ||
| 1254 | a transaction in a given engine is read-write and will not | ||
| 1255 | involve the two-phase commit protocol! | ||
| 1256 | |||
| 1257 | At the end of a statement, server call trans_commit_stmt is | ||
| 1258 | invoked. This call in turn invokes handlerton::prepare() | ||
| 1259 | for every involved engine. Prepare is followed by a call | ||
| 1260 | to handlerton::commit_one_phase() If a one-phase commit | ||
| 1261 | will suffice, handlerton::prepare() is not invoked and | ||
| 1262 | the server only calls handlerton::commit_one_phase(). | ||
| 1263 | At statement commit, the statement-related read-write | ||
| 1264 | engine flag is propagated to the corresponding flag in the | ||
| 1265 | normal transaction. When the commit is complete, the list | ||
| 1266 | of registered engines is cleared. | ||
| 1267 | |||
| 1268 | Rollback is handled in a similar fashion. | ||
| 1269 | |||
| 1270 | Additional notes on DDL and the normal transaction. | ||
| 1271 | --------------------------------------------------- | ||
| 1272 | |||
| 1273 | DDLs and operations with non-transactional engines | ||
| 1274 | do not "register" in thd->transaction lists, and thus do not | ||
| 1275 | modify the transaction state. Besides, each DDL in | ||
| 1276 | MySQL is prefixed with an implicit normal transaction commit | ||
| 1277 | (a call to trans_commit_implicit()), and thus leaves nothing | ||
| 1278 | to modify. | ||
| 1279 | However, as it has been pointed out with CREATE TABLE .. SELECT, | ||
| 1280 | some DDL statements can start a *new* transaction. | ||
| 1281 | |||
| 1282 | Behaviour of the server in this case is currently badly | ||
| 1283 | defined. | ||
| 1284 | DDL statements use a form of "semantic" logging | ||
| 1285 | to maintain atomicity: if CREATE TABLE .. SELECT failed, | ||
| 1286 | the newly created table is deleted. | ||
| 1287 | In addition, some DDL statements issue interim transaction | ||
| 1288 | commits: e.g. ALTER TABLE issues a commit after data is copied | ||
| 1289 | from the original table to the internal temporary table. Other | ||
| 1290 | statements, e.g. CREATE TABLE ... SELECT do not always commit | ||
| 1291 | after itself. | ||
| 1292 | And finally there is a group of DDL statements such as | ||
| 1293 | RENAME/DROP TABLE that doesn't start a new transaction | ||
| 1294 | and doesn't commit. | ||
| 1295 | |||
| 1296 | This diversity makes it hard to say what will happen if | ||
| 1297 | by chance a stored function is invoked during a DDL -- | ||
| 1298 | whether any modifications it makes will be committed or not | ||
| 1299 | is not clear. Fortunately, SQL grammar of few DDLs allows | ||
| 1300 | invocation of a stored function. | ||
| 1301 | |||
| 1302 | A consistent behaviour is perhaps to always commit the normal | ||
| 1303 | transaction after all DDLs, just like the statement transaction | ||
| 1304 | is always committed at the end of all statements. | ||
| 1305 | */ | ||
| 1306 | |||
| 1307 | /** | ||
| 1308 | Register a storage engine for a transaction. | ||
| 1309 | |||
| 1310 | Every storage engine MUST call this function when it starts | ||
| 1311 | a transaction or a statement (that is it must be called both for the | ||
| 1312 | "beginning of transaction" and "beginning of statement"). | ||
| 1313 | Only storage engines registered for the transaction/statement | ||
| 1314 | will know when to commit/rollback it. | ||
| 1315 | |||
| 1316 | @note | ||
| 1317 | trans_register_ha is idempotent - storage engine may register many | ||
| 1318 | times per transaction. | ||
| 1319 | |||
| 1320 | */ | ||
| 1321 | 117373248 | void trans_register_ha(THD *thd, bool all, handlerton *ht_arg, | |
| 1322 | const ulonglong *trxid [[maybe_unused]]) { | ||
| 1323 | Ha_trx_info *ha_info; | ||
| 1324 | 117373248 | Transaction_ctx *trn_ctx = thd->get_transaction(); | |
| 1325 | 117374371 | Transaction_ctx::enum_trx_scope trx_scope = | |
| 1326 |
2/2✓ Branch 0 taken 4242345 times.
✓ Branch 1 taken 113132026 times.
|
117374371 | all ? Transaction_ctx::SESSION : Transaction_ctx::STMT; |
| 1327 | |||
| 1328 |
1/2✓ Branch 0 taken 117375245 times.
✗ Branch 1 not taken.
|
117374371 | DBUG_TRACE; |
| 1329 |
7/10✓ Branch 0 taken 117375056 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117374546 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6686 times.
✓ Branch 5 taken 117367860 times.
✓ Branch 6 taken 201 times.
✓ Branch 7 taken 6485 times.
✓ Branch 8 taken 6686 times.
✗ Branch 9 not taken.
|
117375245 | DBUG_PRINT("enter", ("%s", all ? "all" : "stmt")); |
| 1330 | |||
| 1331 |
2/2✓ Branch 0 taken 4242338 times.
✓ Branch 1 taken 113132208 times.
|
117374546 | if (all) { |
| 1332 | /* | ||
| 1333 | Ensure no active backup engine data exists, unless the current | ||
| 1334 | transaction is from replication and in active xa state. | ||
| 1335 | */ | ||
| 1336 |
4/6✓ Branch 0 taken 4242474 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 344 times.
✓ Branch 3 taken 4242130 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 344 times.
|
4242338 | assert( |
| 1337 | thd->get_ha_data(ht_arg->slot)->ha_ptr_backup == nullptr || | ||
| 1338 | (thd->get_transaction()->xid_state()->has_state(XID_STATE::XA_ACTIVE))); | ||
| 1339 |
6/8✓ Branch 0 taken 4242349 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 344 times.
✓ Branch 3 taken 4242005 times.
✓ Branch 4 taken 340 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 340 times.
|
4242474 | assert(thd->get_ha_data(ht_arg->slot)->ha_ptr_backup == nullptr || |
| 1340 | (thd->is_binlog_applier() || thd->slave_thread)); | ||
| 1341 | |||
| 1342 | 4242349 | thd->server_status |= SERVER_STATUS_IN_TRANS; | |
| 1343 |
2/2✓ Branch 0 taken 1410 times.
✓ Branch 1 taken 4240939 times.
|
4242349 | if (thd->tx_read_only) |
| 1344 | 1410 | thd->server_status |= SERVER_STATUS_IN_TRANS_READONLY; | |
| 1345 |
5/8✓ Branch 0 taken 4242120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4242372 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 207 times.
✓ Branch 5 taken 4242165 times.
✓ Branch 6 taken 207 times.
✗ Branch 7 not taken.
|
4242349 | DBUG_PRINT("info", ("setting SERVER_STATUS_IN_TRANS")); |
| 1346 | } | ||
| 1347 | |||
| 1348 |
3/4✓ Branch 0 taken 117374198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4242445 times.
✓ Branch 3 taken 113131753 times.
|
117374580 | ha_info = thd->get_ha_data(ht_arg->slot)->ha_info + (all ? 1 : 0); |
| 1349 | |||
| 1350 |
2/2✓ Branch 0 taken 83722432 times.
✓ Branch 1 taken 33651861 times.
|
117374198 | if (ha_info->is_started()) { |
| 1351 |
3/6✓ Branch 0 taken 83722411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 83722411 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 83722411 times.
|
83722432 | assert(trn_ctx->ha_trx_info(trx_scope)); |
| 1352 | 83722393 | return; /* already registered, return */ | |
| 1353 | } | ||
| 1354 | |||
| 1355 |
1/2✓ Branch 0 taken 33652885 times.
✗ Branch 1 not taken.
|
33651861 | trn_ctx->register_ha(trx_scope, ha_info, ht_arg); |
| 1356 |
1/2✓ Branch 0 taken 33652623 times.
✗ Branch 1 not taken.
|
33652885 | trn_ctx->set_ha_trx_info(trx_scope, ha_info); |
| 1357 | |||
| 1358 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33652623 times.
|
33652623 | if (ht_arg->prepare == nullptr) trn_ctx->set_no_2pc(trx_scope, true); |
| 1359 | |||
| 1360 |
1/2✓ Branch 0 taken 33652744 times.
✗ Branch 1 not taken.
|
33652623 | trn_ctx->xid_state()->set_query_id(thd->query_id); |
| 1361 | /* | ||
| 1362 | Register transaction start in performance schema if not done already. | ||
| 1363 | By doing this, we handle cases when the transaction is started | ||
| 1364 | implicitly in autocommit=0 mode, and cases when we are in normal autocommit=1 | ||
| 1365 | mode and the executed statement is a single-statement transaction. | ||
| 1366 | |||
| 1367 | Explicitly started transactions are handled in trans_begin(). | ||
| 1368 | |||
| 1369 | Do not register transactions in which binary log is the only | ||
| 1370 | participating transactional storage engine. | ||
| 1371 | */ | ||
| 1372 | #ifdef HAVE_PSI_TRANSACTION_INTERFACE | ||
| 1373 |
2/2✓ Branch 0 taken 22269312 times.
✓ Branch 1 taken 303691 times.
|
22573003 | if (thd->m_transaction_psi == nullptr && ht_arg->db_type != DB_TYPE_BINLOG && |
| 1374 | #ifdef WITH_WSREP | ||
| 1375 | /* Do not register transactions for WSREP engine, it would be done by the | ||
| 1376 | base transactional storage engine (InnoDB). */ | ||
| 1377 |
6/6✓ Branch 0 taken 22573003 times.
✓ Branch 1 taken 11079741 times.
✓ Branch 2 taken 22269286 times.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 7049283 times.
✓ Branch 5 taken 26603329 times.
|
78494901 | ht_arg->db_type != DB_TYPE_WSREP && |
| 1378 | #endif /* WITH_WSREP */ | ||
| 1379 |
2/2✓ Branch 0 taken 7049230 times.
✓ Branch 1 taken 15219924 times.
|
22269286 | !thd->is_attachable_transaction_active()) { |
| 1380 | 7049283 | const XID *xid = trn_ctx->xid_state()->get_xid(); | |
| 1381 | 7049341 | bool autocommit = !thd->in_multi_stmt_transaction_mode(); | |
| 1382 |
1/2✓ Branch 0 taken 7048732 times.
✗ Branch 1 not taken.
|
7049245 | thd->m_transaction_psi = MYSQL_START_TRANSACTION( |
| 1383 | &thd->m_transaction_state, xid, trxid, thd->tx_isolation, | ||
| 1384 | thd->tx_read_only, autocommit); | ||
| 1385 |
3/4✓ Branch 0 taken 5063954 times.
✓ Branch 1 taken 1984895 times.
✓ Branch 2 taken 5064470 times.
✗ Branch 3 not taken.
|
7048732 | DEBUG_SYNC(thd, "after_set_transaction_psi_before_set_transaction_gtid"); |
| 1386 |
1/2✓ Branch 0 taken 7049339 times.
✗ Branch 1 not taken.
|
7049365 | gtid_set_performance_schema_values(thd); |
| 1387 | } | ||
| 1388 | #endif | ||
| 1389 |
2/2✓ Branch 0 taken 33652945 times.
✓ Branch 1 taken 83722440 times.
|
117375061 | } |
| 1390 | |||
| 1391 | /** | ||
| 1392 | Check if we can skip the two-phase commit. | ||
| 1393 | |||
| 1394 | A helper function to evaluate if two-phase commit is mandatory. | ||
| 1395 | As a side effect, propagates the read-only/read-write flags | ||
| 1396 | of the statement transaction to its enclosing normal transaction. | ||
| 1397 | |||
| 1398 | If we have at least two engines with read-write changes we must | ||
| 1399 | run a two-phase commit. Otherwise we can run several independent | ||
| 1400 | commits as the only transactional engine has read-write changes | ||
| 1401 | and others are read-only. | ||
| 1402 | |||
| 1403 | @retval 0 All engines are read-only. | ||
| 1404 | @retval 1 We have the only engine with read-write changes. | ||
| 1405 | @retval >1 More than one engine have read-write changes. | ||
| 1406 | Note: return value might NOT be the exact number of | ||
| 1407 | engines with read-write changes. | ||
| 1408 | */ | ||
| 1409 | |||
| 1410 | 12799774 | static uint ha_check_and_coalesce_trx_read_only(THD *thd, | |
| 1411 | Ha_trx_info_list &ha_list, | ||
| 1412 | bool all) { | ||
| 1413 | /* The number of storage engines that have actual changes. */ | ||
| 1414 | 12799774 | unsigned rw_ha_count = 0; | |
| 1415 | |||
| 1416 |
7/12✓ Branch 0 taken 12799950 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12800031 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17779076 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17243754 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 30043043 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 17779004 times.
✓ Branch 11 taken 12264039 times.
|
30043308 | for (auto const &ha_info : ha_list) { |
| 1417 |
3/4✓ Branch 0 taken 17779334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15894844 times.
✓ Branch 3 taken 1884490 times.
|
17779076 | if (ha_info.is_trx_read_write()) ++rw_ha_count; |
| 1418 | |||
| 1419 |
2/2✓ Branch 0 taken 16007357 times.
✓ Branch 1 taken 1771977 times.
|
17779334 | if (!all) { |
| 1420 | Ha_trx_info *ha_info_all = | ||
| 1421 |
1/2✓ Branch 0 taken 16007714 times.
✗ Branch 1 not taken.
|
16007357 | &thd->get_ha_data(ha_info.ht()->slot)->ha_info[1]; |
| 1422 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16007714 times.
|
16007714 | assert(&ha_info != ha_info_all); |
| 1423 | /* | ||
| 1424 | Merge read-only/read-write information about statement | ||
| 1425 | transaction to its enclosing normal transaction. Do this | ||
| 1426 | only if in a real transaction -- that is, if we know | ||
| 1427 | that ha_info_all is registered in thd->transaction.all. | ||
| 1428 | Since otherwise we only clutter the normal transaction flags. | ||
| 1429 | */ | ||
| 1430 |
2/2✓ Branch 0 taken 10569854 times.
✓ Branch 1 taken 5437871 times.
|
16007714 | if (ha_info_all->is_started()) /* false if autocommit. */ |
| 1431 |
1/2✓ Branch 0 taken 10569838 times.
✗ Branch 1 not taken.
|
10569854 | ha_info_all->coalesce_trx_with(ha_info); |
| 1432 |
2/2✓ Branch 0 taken 536152 times.
✓ Branch 1 taken 1235825 times.
|
1771977 | } else if (rw_ha_count > 1) { |
| 1433 | /* | ||
| 1434 | It is a normal transaction, so we don't need to merge read/write | ||
| 1435 | information up, and the need for two-phase commit has been | ||
| 1436 | already established. Break the loop prematurely. | ||
| 1437 | */ | ||
| 1438 | 536152 | break; | |
| 1439 | } | ||
| 1440 | 12800191 | } | |
| 1441 | 12799863 | return rw_ha_count; | |
| 1442 | } | ||
| 1443 | |||
| 1444 | /** | ||
| 1445 | The function computes condition to call gtid persistor wrapper, | ||
| 1446 | and executes it. | ||
| 1447 | It is invoked at committing a statement or transaction, including XA, | ||
| 1448 | and also at XA prepare handling. | ||
| 1449 | |||
| 1450 | @param thd Thread context. | ||
| 1451 | @param all The execution scope, true for the transaction one, false | ||
| 1452 | for the statement one. | ||
| 1453 | |||
| 1454 | @return std::pair containing: Error and Owned GTID release status | ||
| 1455 | Error | ||
| 1456 | @retval 0 Ok | ||
| 1457 | @retval !0 Error | ||
| 1458 | |||
| 1459 | Owned GTID release status | ||
| 1460 | @retval true remove the GTID owned by thread from owned GTIDs | ||
| 1461 | @retval false removal of the GTID owned by thread from owned GTIDs | ||
| 1462 | is not required | ||
| 1463 | */ | ||
| 1464 | |||
| 1465 | 15548245 | std::pair<int, bool> commit_owned_gtids(THD *thd, bool all) { | |
| 1466 |
1/2✓ Branch 0 taken 15548939 times.
✗ Branch 1 not taken.
|
15548245 | DBUG_TRACE; |
| 1467 | 15548939 | int error = 0; | |
| 1468 | 15548939 | bool need_clear_owned_gtid = false; | |
| 1469 | |||
| 1470 | /* | ||
| 1471 | If the binary log is disabled for this thread (either by | ||
| 1472 | log_bin=0 or sql_log_bin=0 or by log_replica_updates=0 for a | ||
| 1473 | slave thread), then the statement will not be written to | ||
| 1474 | the binary log. In this case, we should save its GTID into | ||
| 1475 | mysql.gtid_executed table and @@GLOBAL.GTID_EXECUTED as it | ||
| 1476 | did when binlog is enabled. | ||
| 1477 | |||
| 1478 | We also skip saving GTID into mysql.gtid_executed table and | ||
| 1479 | @@GLOBAL.GTID_EXECUTED when replica-preserve-commit-order is enabled. We | ||
| 1480 | skip as GTID will be saved in | ||
| 1481 | Commit_order_manager::flush_engine_and_signal_threads (invoked from | ||
| 1482 | Commit_order_manager::wait_and_finish). In particular, there is the | ||
| 1483 | following call stack under ha_commit_low which save GTID in case its skipped | ||
| 1484 | here: | ||
| 1485 | |||
| 1486 | ha_commit_low -> | ||
| 1487 | Commit_order_manager::wait_and_finish -> | ||
| 1488 | Commit_order_manager::finish -> | ||
| 1489 | Commit_order_manager::flush_engine_and_signal_threads -> | ||
| 1490 | Gtid_state::update_commit_group | ||
| 1491 | |||
| 1492 | We also skip saving GTID for intermediate commits i.e. when | ||
| 1493 | thd->is_operating_substatement_implicitly is enabled. | ||
| 1494 | */ | ||
| 1495 |
1/2✓ Branch 0 taken 15548649 times.
✗ Branch 1 not taken.
|
15548939 | if (thd->is_current_stmt_binlog_log_replica_updates_disabled() && |
| 1496 |
9/10✓ Branch 0 taken 6223238 times.
✓ Branch 1 taken 9325411 times.
✓ Branch 2 taken 6223238 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2180654 times.
✓ Branch 5 taken 4042584 times.
✓ Branch 6 taken 2156515 times.
✓ Branch 7 taken 24139 times.
✓ Branch 8 taken 1960343 times.
✓ Branch 9 taken 13588306 times.
|
17705164 | ending_trans(thd, all) && !thd->is_operating_gtid_table_implicitly && |
| 1497 |
2/2✓ Branch 0 taken 1960343 times.
✓ Branch 1 taken 196172 times.
|
2156515 | !thd->is_operating_substatement_implicitly) { |
| 1498 |
5/6✓ Branch 0 taken 1960343 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1954576 times.
✓ Branch 3 taken 5767 times.
✓ Branch 4 taken 194 times.
✓ Branch 5 taken 1960149 times.
|
3914919 | if (!has_commit_order_manager(thd) && |
| 1499 |
2/2✓ Branch 0 taken 1954405 times.
✓ Branch 1 taken 171 times.
|
1954576 | (thd->owned_gtid.sidno > 0 || |
| 1500 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 1954382 times.
|
1954405 | thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS)) { |
| 1501 | 194 | need_clear_owned_gtid = true; | |
| 1502 | } | ||
| 1503 | |||
| 1504 | /* | ||
| 1505 | If GTID is not persisted by SE, write it to | ||
| 1506 | mysql.gtid_executed table. | ||
| 1507 | */ | ||
| 1508 |
7/8✓ Branch 0 taken 2592 times.
✓ Branch 1 taken 1957751 times.
✓ Branch 2 taken 2592 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 201 times.
✓ Branch 5 taken 2391 times.
✓ Branch 6 taken 201 times.
✓ Branch 7 taken 1960142 times.
|
1960343 | if (thd->owned_gtid.sidno > 0 && !thd->se_persists_gtid()) { |
| 1509 |
1/2✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
|
201 | error = gtid_state->save(thd); |
| 1510 | } | ||
| 1511 | } | ||
| 1512 | |||
| 1513 |
1/2✓ Branch 0 taken 15548587 times.
✗ Branch 1 not taken.
|
31097679 | return std::make_pair(error, need_clear_owned_gtid); |
| 1514 | 15548587 | } | |
| 1515 | |||
| 1516 | /** | ||
| 1517 | @param[in] thd Thread handle. | ||
| 1518 | @param[in] all Session transaction if true, statement | ||
| 1519 | otherwise. | ||
| 1520 | @param[in] ignore_global_read_lock Allow commit to complete even if a | ||
| 1521 | global read lock is active. This can be | ||
| 1522 | used to allow changes to internal tables | ||
| 1523 | (e.g. slave status tables). | ||
| 1524 | |||
| 1525 | @retval | ||
| 1526 | 0 ok | ||
| 1527 | @retval | ||
| 1528 | 1 transaction was rolled back | ||
| 1529 | @retval | ||
| 1530 | 2 error during commit, data may be inconsistent | ||
| 1531 | |||
| 1532 | @todo | ||
| 1533 | Since we don't support nested statement transactions in 5.0, | ||
| 1534 | we can't commit or rollback stmt transactions while we are inside | ||
| 1535 | stored functions or triggers. So we simply do nothing now. | ||
| 1536 | TODO: This should be fixed in later ( >= 5.1) releases. | ||
| 1537 | */ | ||
| 1538 | |||
| 1539 | 15546411 | int ha_commit_trans(THD *thd, bool all, bool ignore_global_read_lock) { | |
| 1540 | 15546411 | int error = 0; | |
| 1541 | #ifdef WITH_WSREP | ||
| 1542 |
2/2✓ Branch 0 taken 15269884 times.
✓ Branch 1 taken 276527 times.
|
15546411 | if (!thd->wsrep_applier) { |
| 1543 | /* While running in applier mode, PXC continue to retain its own | ||
| 1544 | stage information as it has better stage tracking. */ | ||
| 1545 |
1/2✓ Branch 0 taken 15270532 times.
✗ Branch 1 not taken.
|
15269884 | THD_STAGE_INFO(thd, stage_waiting_for_handler_commit); |
| 1546 | } | ||
| 1547 | #else | ||
| 1548 | THD_STAGE_INFO(thd, stage_waiting_for_handler_commit); | ||
| 1549 | #endif /* WITH_WSREP */ | ||
| 1550 | |||
| 1551 | 15547059 | bool run_slave_post_commit = false; | |
| 1552 | 15547059 | bool need_clear_owned_gtid = false; | |
| 1553 | /* | ||
| 1554 | Save transaction owned gtid into table before transaction prepare | ||
| 1555 | if binlog is disabled, or binlog is enabled and log_replica_updates | ||
| 1556 | is disabled with slave SQL thread or slave worker thread. | ||
| 1557 | */ | ||
| 1558 |
1/2✓ Branch 0 taken 15547666 times.
✗ Branch 1 not taken.
|
15547059 | std::tie(error, need_clear_owned_gtid) = commit_owned_gtids(thd, all); |
| 1559 | |||
| 1560 | /* | ||
| 1561 | 'all' means that this is either an explicit commit issued by | ||
| 1562 | user, or an implicit commit issued by a DDL. | ||
| 1563 | */ | ||
| 1564 | 15547485 | Transaction_ctx *trn_ctx = thd->get_transaction(); | |
| 1565 | 15547476 | Transaction_ctx::enum_trx_scope trx_scope = | |
| 1566 |
2/2✓ Branch 0 taken 3969600 times.
✓ Branch 1 taken 11577876 times.
|
15547476 | all ? Transaction_ctx::SESSION : Transaction_ctx::STMT; |
| 1567 | |||
| 1568 | /* | ||
| 1569 | "real" is a nick name for a transaction for which a commit will | ||
| 1570 | make persistent changes. E.g. a 'stmt' transaction inside a 'all' | ||
| 1571 | transaction is not 'real': even though it's possible to commit it, | ||
| 1572 | the changes are not durable as they might be rolled back if the | ||
| 1573 | enclosing 'all' transaction is rolled back. | ||
| 1574 | */ | ||
| 1575 |
4/4✓ Branch 0 taken 11577877 times.
✓ Branch 1 taken 3969599 times.
✓ Branch 2 taken 3939420 times.
✓ Branch 3 taken 7638481 times.
|
15547476 | bool is_real_trans = all || !trn_ctx->is_active(Transaction_ctx::SESSION); |
| 1576 | #ifndef NDEBUG | ||
| 1577 | 15547500 | bool transaction_to_skip = false; | |
| 1578 |
4/6✓ Branch 0 taken 15547199 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3564 times.
✓ Branch 3 taken 15543635 times.
✓ Branch 4 taken 3564 times.
✗ Branch 5 not taken.
|
15547500 | DBUG_EXECUTE_IF("replica_crash_after_commit", { |
| 1579 | transaction_to_skip = is_already_logged_transaction(thd); | ||
| 1580 | }); | ||
| 1581 | #endif // NDEBUG | ||
| 1582 |
1/2✓ Branch 0 taken 15546649 times.
✗ Branch 1 not taken.
|
15547199 | auto ha_info = trn_ctx->ha_trx_info(trx_scope); |
| 1583 | 15546649 | XID_STATE *xid_state = trn_ctx->xid_state(); | |
| 1584 | |||
| 1585 |
1/2✓ Branch 0 taken 15547589 times.
✗ Branch 1 not taken.
|
15547037 | DBUG_TRACE; |
| 1586 | |||
| 1587 |
6/10✓ Branch 0 taken 15547477 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15547514 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 438 times.
✓ Branch 5 taken 15547076 times.
✓ Branch 6 taken 438 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 438 times.
✗ Branch 9 not taken.
|
15547589 | DBUG_PRINT("info", ("all=%d thd->in_sub_stmt=%d ha_info=%p is_real_trans=%d", |
| 1588 | all, thd->in_sub_stmt, ha_info.head(), is_real_trans)); | ||
| 1589 | /* | ||
| 1590 | We must not commit the normal transaction if a statement | ||
| 1591 | transaction is pending. Otherwise statement transaction | ||
| 1592 | flags will not get propagated to its normal transaction's | ||
| 1593 | counterpart. | ||
| 1594 | */ | ||
| 1595 |
3/4✓ Branch 0 taken 11566386 times.
✓ Branch 1 taken 3981079 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11566386 times.
|
15547514 | assert(!trn_ctx->is_active(Transaction_ctx::STMT) || !all); |
| 1596 | |||
| 1597 |
3/6✓ Branch 0 taken 15547407 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 15547403 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
15547465 | DBUG_EXECUTE_IF("pre_commit_error", { |
| 1598 | error = true; | ||
| 1599 | my_error(ER_UNKNOWN_ERROR, MYF(0)); | ||
| 1600 | }); | ||
| 1601 | |||
| 1602 | /* | ||
| 1603 | When atomic DDL is executed on the slave, we would like to | ||
| 1604 | to update slave applier state as part of DDL's transaction. | ||
| 1605 | Call Relay_log_info::pre_commit() hook to do this before DDL | ||
| 1606 | gets committed in the following block. | ||
| 1607 | Failed atomic DDL statements should've been marked as executed/committed | ||
| 1608 | during statement rollback, though some like GRANT may continue until | ||
| 1609 | this point. | ||
| 1610 | When applying a DDL statement on a slave and the statement is filtered | ||
| 1611 | out by a table filter, we report an error "ER_SLAVE_IGNORED_TABLE" to | ||
| 1612 | warn slave applier thread. We need to save the DDL statement's gtid | ||
| 1613 | into mysql.gtid_executed system table if the binary log is disabled | ||
| 1614 | on the slave and gtids are enabled. | ||
| 1615 | */ | ||
| 1616 |
7/8✓ Branch 0 taken 7908946 times.
✓ Branch 1 taken 7638343 times.
✓ Branch 2 taken 7908699 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24288 times.
✓ Branch 5 taken 7884411 times.
✓ Branch 6 taken 24287 times.
✓ Branch 7 taken 15522755 times.
|
15571577 | if (is_real_trans && is_atomic_ddl_commit_on_slave(thd) && |
| 1617 |
3/4✓ Branch 0 taken 24288 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 24285 times.
|
24288 | (!thd->is_error() || |
| 1618 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
5 | (thd->is_operating_gtid_table_implicitly && |
| 1619 | 2 | thd->get_stmt_da()->mysql_errno() == ER_SLAVE_IGNORED_TABLE))) { | |
| 1620 | 24287 | run_slave_post_commit = true; | |
| 1621 |
3/6✓ Branch 0 taken 24287 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24287 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 24287 times.
|
24287 | error = error || thd->rli_slave->pre_commit(); |
| 1622 | |||
| 1623 |
4/6✓ Branch 0 taken 24287 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 24285 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
24287 | DBUG_EXECUTE_IF("rli_pre_commit_error", { |
| 1624 | error = true; | ||
| 1625 | my_error(ER_UNKNOWN_ERROR, MYF(0)); | ||
| 1626 | }); | ||
| 1627 |
4/6✓ Branch 0 taken 24287 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 24243 times.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
|
24287 | DBUG_EXECUTE_IF("replica_crash_before_commit", { |
| 1628 | /* This pre-commit crash aims solely at atomic DDL */ | ||
| 1629 | DBUG_SUICIDE(); | ||
| 1630 | }); | ||
| 1631 | } | ||
| 1632 | |||
| 1633 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15546998 times.
|
15546998 | if (thd->in_sub_stmt) { |
| 1634 | ✗ | assert(0); | |
| 1635 | /* | ||
| 1636 | Since we don't support nested statement transactions in 5.0, | ||
| 1637 | we can't commit or rollback stmt transactions while we are inside | ||
| 1638 | stored functions or triggers. So we simply do nothing now. | ||
| 1639 | TODO: This should be fixed in later ( >= 5.1) releases. | ||
| 1640 | */ | ||
| 1641 | if (!all) return 0; | ||
| 1642 | /* | ||
| 1643 | We assume that all statements which commit or rollback main transaction | ||
| 1644 | are prohibited inside of stored functions or triggers. So they should | ||
| 1645 | bail out with error even before ha_commit_trans() call. To be 100% safe | ||
| 1646 | let us throw error in non-debug builds. | ||
| 1647 | */ | ||
| 1648 | my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); | ||
| 1649 | return 2; | ||
| 1650 | } | ||
| 1651 | |||
| 1652 | 15546998 | MDL_request mdl_request; | |
| 1653 | 15547288 | bool release_mdl = false; | |
| 1654 | #ifdef WITH_WSREP | ||
| 1655 | 15547288 | uint rw_ha_count = 0; | |
| 1656 | #endif /* WITH_WSREP */ | ||
| 1657 |
6/8✓ Branch 0 taken 15547119 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12799858 times.
✓ Branch 3 taken 2747261 times.
✓ Branch 4 taken 12799875 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12799898 times.
✓ Branch 7 taken 2747221 times.
|
15547288 | if (ha_info && !error) { |
| 1658 | #ifndef WITH_WSREP | ||
| 1659 | uint rw_ha_count = 0; | ||
| 1660 | #endif /* !!!!!WITH_WSREP */ | ||
| 1661 | bool rw_trans; | ||
| 1662 | |||
| 1663 |
4/6✓ Branch 0 taken 12800014 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 12799985 times.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
|
12799898 | DBUG_EXECUTE_IF("crash_commit_before", DBUG_SUICIDE();); |
| 1664 | |||
| 1665 | /* | ||
| 1666 | skip 2PC if the transaction is empty and it is not marked as started (which | ||
| 1667 | can happen when the slave's binlog is disabled) | ||
| 1668 | */ | ||
| 1669 |
2/4✓ Branch 0 taken 12799827 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12799829 times.
✗ Branch 3 not taken.
|
12799985 | if (ha_info->is_started()) |
| 1670 |
1/2✓ Branch 0 taken 12799978 times.
✗ Branch 1 not taken.
|
12799829 | rw_ha_count = ha_check_and_coalesce_trx_read_only(thd, ha_info, all); |
| 1671 | 12799955 | trn_ctx->set_rw_ha_count(trx_scope, rw_ha_count); | |
| 1672 | /* rw_trans is true when we in a transaction changing data */ | ||
| 1673 |
4/4✓ Branch 0 taken 5161509 times.
✓ Branch 1 taken 7638425 times.
✓ Branch 2 taken 3465113 times.
✓ Branch 3 taken 1696396 times.
|
12799934 | rw_trans = is_real_trans && (rw_ha_count > 0); |
| 1674 | |||
| 1675 |
5/8✓ Branch 0 taken 12799825 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 12799823 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
|
12799934 | DBUG_EXECUTE_IF("dbug.enabled_commit", { |
| 1676 | const char act[] = "now signal Reached wait_for signal.commit_continue"; | ||
| 1677 | assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act))); | ||
| 1678 | };); | ||
| 1679 |
3/4✓ Branch 0 taken 10707022 times.
✓ Branch 1 taken 2092557 times.
✓ Branch 2 taken 10707634 times.
✗ Branch 3 not taken.
|
12799825 | DEBUG_SYNC(thd, "ha_commit_trans_before_acquire_commit_lock"); |
| 1680 |
4/4✓ Branch 0 taken 3465250 times.
✓ Branch 1 taken 9334941 times.
✓ Branch 2 taken 3022746 times.
✓ Branch 3 taken 442504 times.
|
12800191 | if (rw_trans && !ignore_global_read_lock) { |
| 1681 | /* | ||
| 1682 | Acquire a metadata lock which will ensure that COMMIT is blocked | ||
| 1683 | by an active FLUSH TABLES WITH READ LOCK (and vice versa: | ||
| 1684 | COMMIT in progress blocks FTWRL). | ||
| 1685 | |||
| 1686 | We allow the owner of FTWRL to COMMIT; we assume that it knows | ||
| 1687 | what it does. | ||
| 1688 | */ | ||
| 1689 |
1/2✓ Branch 0 taken 3022689 times.
✗ Branch 1 not taken.
|
3022746 | MDL_REQUEST_INIT(&mdl_request, MDL_key::COMMIT, "", "", |
| 1690 | MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT); | ||
| 1691 | |||
| 1692 |
5/8✓ Branch 0 taken 3022565 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3022560 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 121 times.
✓ Branch 5 taken 3022439 times.
✓ Branch 6 taken 121 times.
✗ Branch 7 not taken.
|
3022689 | DBUG_PRINT("debug", ("Acquire MDL commit lock")); |
| 1693 | #ifdef WITH_WSREP | ||
| 1694 | /* Taking explicit lock will block background/applier thread from aborting | ||
| 1695 | a local thread lock so avoid taking this lock here. | ||
| 1696 | Lock is meant to protect commit against FLUSH TABLE WITH READ LOCK | ||
| 1697 | that may get fired when COMMIT is active. */ | ||
| 1698 |
12/14✓ Branch 0 taken 3022561 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 396670 times.
✓ Branch 3 taken 2625891 times.
✓ Branch 4 taken 118166 times.
✓ Branch 5 taken 278504 times.
✓ Branch 6 taken 3395 times.
✓ Branch 7 taken 114771 times.
✓ Branch 8 taken 2908174 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 2908173 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 3022944 times.
|
3022560 | if (!WSREP(thd) && thd->mdl_context.acquire_lock( |
| 1699 | &mdl_request, thd->variables.lock_wait_timeout)) { | ||
| 1700 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | ha_rollback_trans(thd, all); |
| 1701 | 1 | return 1; | |
| 1702 | } | ||
| 1703 | #else | ||
| 1704 | if (thd->mdl_context.acquire_lock(&mdl_request, | ||
| 1705 | thd->variables.lock_wait_timeout)) { | ||
| 1706 | ha_rollback_trans(thd, all); | ||
| 1707 | return 1; | ||
| 1708 | } | ||
| 1709 | #endif /* WITH_WSREP */ | ||
| 1710 | 3022944 | release_mdl = true; | |
| 1711 | |||
| 1712 |
3/4✓ Branch 0 taken 2918001 times.
✓ Branch 1 taken 104940 times.
✓ Branch 2 taken 2917772 times.
✗ Branch 3 not taken.
|
3022944 | DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock"); |
| 1713 | } | ||
| 1714 | |||
| 1715 |
7/8✓ Branch 0 taken 3465451 times.
✓ Branch 1 taken 9334706 times.
✓ Branch 2 taken 3465454 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3118282 times.
✓ Branch 5 taken 347172 times.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 12800141 times.
|
15918425 | if (rw_trans && stmt_has_updated_trans_table(ha_info) && |
| 1716 |
3/4✓ Branch 0 taken 3118268 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 3118263 times.
|
3118282 | check_readonly(thd, true)) { |
| 1717 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | ha_rollback_trans(thd, all); |
| 1718 | 5 | error = 1; | |
| 1719 | 5 | goto end; | |
| 1720 | } | ||
| 1721 | |||
| 1722 | #ifdef WITH_WSREP | ||
| 1723 |
5/6✓ Branch 0 taken 12800165 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4973637 times.
✓ Branch 3 taken 7826587 times.
✓ Branch 4 taken 4973632 times.
✓ Branch 5 taken 7826575 times.
|
12800141 | if (!trn_ctx->no_2pc(trx_scope) && (trn_ctx->rw_ha_count(trx_scope) > 1)) |
| 1724 |
1/2✓ Branch 0 taken 4973629 times.
✗ Branch 1 not taken.
|
4973632 | error = tc_log->prepare(thd, all); |
| 1725 |
5/6✓ Branch 0 taken 7826608 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5948190 times.
✓ Branch 3 taken 1878445 times.
✓ Branch 4 taken 5948181 times.
✓ Branch 5 taken 1878454 times.
|
15653210 | else if (trn_ctx->no_2pc(trx_scope) || |
| 1726 | 7826608 | trn_ctx->rw_ha_count(trx_scope) == 1) { | |
| 1727 | /* cache decision to run wsrep-commit-hook with log_bin=off. */ | ||
| 1728 |
1/2✓ Branch 0 taken 5948266 times.
✗ Branch 1 not taken.
|
5948181 | thd->run_wsrep_commit_hooks = wsrep_run_commit_hook(thd, all); |
| 1729 | } | ||
| 1730 | #else | ||
| 1731 | if (!trn_ctx->no_2pc(trx_scope) && (trn_ctx->rw_ha_count(trx_scope) > 1)) | ||
| 1732 | error = tc_log->prepare(thd, all); | ||
| 1733 | #endif /* WITH_WSREP */ | ||
| 1734 | } | ||
| 1735 | /* | ||
| 1736 | The state of XA transaction is changed to Prepared, intermediately. | ||
| 1737 | It's going to change to the regular NOTR at the end. | ||
| 1738 | The fact of the Prepared state is of interest to binary logger. | ||
| 1739 | */ | ||
| 1740 |
8/8✓ Branch 0 taken 15547167 times.
✓ Branch 1 taken 403 times.
✓ Branch 2 taken 3969476 times.
✓ Branch 3 taken 11577691 times.
✓ Branch 4 taken 123 times.
✓ Branch 5 taken 3969367 times.
✓ Branch 6 taken 123 times.
✓ Branch 7 taken 15547461 times.
|
15547570 | if (!error && all && xid_state->has_state(XID_STATE::XA_IDLE)) { |
| 1741 |
3/6✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 123 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 123 times.
✗ Branch 5 not taken.
|
123 | assert( |
| 1742 | thd->lex->sql_command == SQLCOM_XA_COMMIT && | ||
| 1743 | static_cast<Sql_cmd_xa_commit *>(thd->lex->m_sql_cmd)->get_xa_opt() == | ||
| 1744 | XA_ONE_PHASE); | ||
| 1745 | |||
| 1746 | 123 | xid_state->set_state(XID_STATE::XA_PREPARED); | |
| 1747 | } | ||
| 1748 | |||
| 1749 | #ifdef WITH_WSREP | ||
| 1750 |
3/4✓ Branch 0 taken 13197875 times.
✓ Branch 1 taken 2349578 times.
✓ Branch 2 taken 13198505 times.
✗ Branch 3 not taken.
|
15547584 | DEBUG_SYNC(thd, "wsrep_before_commit"); |
| 1751 | #endif | ||
| 1752 | |||
| 1753 |
7/8✓ Branch 0 taken 15547384 times.
✓ Branch 1 taken 699 times.
✓ Branch 2 taken 15545498 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 699 times.
✓ Branch 5 taken 15544799 times.
✓ Branch 6 taken 1398 times.
✓ Branch 7 taken 15544799 times.
|
15548083 | if (error || (error = tc_log->commit(thd, all))) { |
| 1754 |
1/2✓ Branch 0 taken 1398 times.
✗ Branch 1 not taken.
|
1398 | ha_rollback_trans(thd, all); |
| 1755 | 1398 | error = 1; | |
| 1756 | 1398 | goto end; | |
| 1757 | } | ||
| 1758 | /* | ||
| 1759 | Mark multi-statement (any autocommit mode) or single-statement | ||
| 1760 | (autocommit=1) transaction as rolled back | ||
| 1761 | */ | ||
| 1762 | #ifdef HAVE_PSI_TRANSACTION_INTERFACE | ||
| 1763 |
4/4✓ Branch 0 taken 7906284 times.
✓ Branch 1 taken 7638515 times.
✓ Branch 2 taken 4831896 times.
✓ Branch 3 taken 3074388 times.
|
15544799 | if (is_real_trans && thd->m_transaction_psi != nullptr) { |
| 1764 |
1/2✓ Branch 0 taken 4831268 times.
✗ Branch 1 not taken.
|
4831896 | MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi); |
| 1765 | 4831268 | thd->m_transaction_psi = nullptr; | |
| 1766 | } | ||
| 1767 | #endif | ||
| 1768 |
5/8✓ Branch 0 taken 15544618 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 15544579 times.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 39 times.
✗ Branch 7 not taken.
|
15544171 | DBUG_EXECUTE_IF("crash_commit_after", |
| 1769 | if (!thd->is_operating_gtid_table_implicitly) | ||
| 1770 | DBUG_SUICIDE();); | ||
| 1771 | 15544579 | end: | |
| 1772 |
4/4✓ Branch 0 taken 3021462 times.
✓ Branch 1 taken 12524520 times.
✓ Branch 2 taken 2906831 times.
✓ Branch 3 taken 114631 times.
|
15545982 | if (release_mdl && mdl_request.ticket) { |
| 1773 | /* | ||
| 1774 | We do not always immediately release transactional locks | ||
| 1775 | after ha_commit_trans() (see uses of ha_enable_transaction()), | ||
| 1776 | thus we release the commit blocker lock as soon as it's | ||
| 1777 | not needed. | ||
| 1778 | */ | ||
| 1779 |
5/8✓ Branch 0 taken 2906478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2906340 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 113 times.
✓ Branch 5 taken 2906227 times.
✓ Branch 6 taken 113 times.
✗ Branch 7 not taken.
|
2906831 | DBUG_PRINT("debug", ("Releasing MDL commit lock")); |
| 1780 |
1/2✓ Branch 0 taken 2907870 times.
✗ Branch 1 not taken.
|
2906340 | thd->mdl_context.release_lock(mdl_request.ticket); |
| 1781 | } | ||
| 1782 | |||
| 1783 | #ifdef WITH_WSREP | ||
| 1784 | /* | ||
| 1785 | New galera flow now start transaction even for read-only transaction. | ||
| 1786 | This read-only transaction will not change any row so will get committed | ||
| 1787 | as an empty transaction | ||
| 1788 | */ | ||
| 1789 |
13/14✓ Branch 0 taken 15546947 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 311856 times.
✓ Branch 3 taken 15235091 times.
✓ Branch 4 taken 171631 times.
✓ Branch 5 taken 140225 times.
✓ Branch 6 taken 171415 times.
✓ Branch 7 taken 216 times.
✓ Branch 8 taken 72449 times.
✓ Branch 9 taken 98966 times.
✓ Branch 10 taken 72429 times.
✓ Branch 11 taken 7 times.
✓ Branch 12 taken 72441 times.
✓ Branch 13 taken 15474493 times.
|
15619457 | if (wsrep_is_active(thd) && is_real_trans && !error && (rw_ha_count == 0) && |
| 1790 | 72449 | wsrep_not_committed(thd)) { | |
| 1791 |
1/2✓ Branch 0 taken 72236 times.
✗ Branch 1 not taken.
|
72441 | wsrep_commit_empty(thd, all); |
| 1792 | } | ||
| 1793 | #endif /* WITH_WSREP */ | ||
| 1794 | |||
| 1795 | /* Free resources and perform other cleanup even for 'empty' transactions. */ | ||
| 1796 |
2/2✓ Branch 0 taken 7908423 times.
✓ Branch 1 taken 7638306 times.
|
15546729 | if (is_real_trans) { |
| 1797 |
1/2✓ Branch 0 taken 7908813 times.
✗ Branch 1 not taken.
|
7908423 | trn_ctx->cleanup(); |
| 1798 | 7908813 | thd->tx_priority = 0; | |
| 1799 | } | ||
| 1800 | |||
| 1801 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 15546975 times.
|
15547119 | if (need_clear_owned_gtid) { |
| 1802 | 144 | thd->server_status &= ~SERVER_STATUS_IN_TRANS; | |
| 1803 | /* | ||
| 1804 | Release the owned GTID when binlog is disabled, or binlog is | ||
| 1805 | enabled and log_replica_updates is disabled with slave SQL thread | ||
| 1806 | or slave worker thread. | ||
| 1807 | */ | ||
| 1808 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 139 times.
|
144 | if (error) |
| 1809 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | gtid_state->update_on_rollback(thd); |
| 1810 | else | ||
| 1811 |
1/2✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
|
139 | gtid_state->update_on_commit(thd); |
| 1812 | } else { | ||
| 1813 |
7/8✓ Branch 0 taken 15546686 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1052369 times.
✓ Branch 3 taken 14494317 times.
✓ Branch 4 taken 159 times.
✓ Branch 5 taken 1052210 times.
✓ Branch 6 taken 159 times.
✓ Branch 7 taken 15546527 times.
|
15546975 | if (has_commit_order_manager(thd) && error) { |
| 1814 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
159 | gtid_state->update_on_rollback(thd); |
| 1815 | } | ||
| 1816 | } | ||
| 1817 |
2/2✓ Branch 0 taken 24143 times.
✓ Branch 1 taken 15522527 times.
|
15546670 | if (run_slave_post_commit) { |
| 1818 |
4/6✓ Branch 0 taken 24143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 24087 times.
✓ Branch 4 taken 56 times.
✗ Branch 5 not taken.
|
24143 | DBUG_EXECUTE_IF("replica_crash_after_commit", DBUG_SUICIDE();); |
| 1819 | |||
| 1820 |
1/2✓ Branch 0 taken 24087 times.
✗ Branch 1 not taken.
|
24087 | thd->rli_slave->post_commit(error != 0); |
| 1821 | /* | ||
| 1822 | SERVER_STATUS_IN_TRANS may've been gained by pre_commit alone | ||
| 1823 | when the main DDL transaction is filtered out of execution. | ||
| 1824 | In such case the status has to be reset now. | ||
| 1825 | |||
| 1826 | TODO: move/refactor this handling onto trans_commit/commit_implicit() | ||
| 1827 | the caller level. | ||
| 1828 | */ | ||
| 1829 | 24087 | thd->server_status &= ~SERVER_STATUS_IN_TRANS; | |
| 1830 | } else { | ||
| 1831 |
17/22✓ Branch 0 taken 15522657 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3508 times.
✓ Branch 3 taken 15519149 times.
✓ Branch 4 taken 1762 times.
✓ Branch 5 taken 1746 times.
✓ Branch 6 taken 1762 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 211 times.
✓ Branch 9 taken 1551 times.
✓ Branch 10 taken 7 times.
✓ Branch 11 taken 204 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 6 times.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 times.
✓ Branch 19 taken 3507 times.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
|
15522527 | DBUG_EXECUTE_IF("replica_crash_after_commit", { |
| 1832 | if (thd->slave_thread && thd->rli_slave && | ||
| 1833 | thd->rli_slave->current_event && | ||
| 1834 | thd->rli_slave->current_event->get_type_code() == | ||
| 1835 | binary_log::XID_EVENT && | ||
| 1836 | !thd->is_operating_substatement_implicitly && | ||
| 1837 | !thd->is_operating_gtid_table_implicitly && !transaction_to_skip) | ||
| 1838 | DBUG_SUICIDE(); | ||
| 1839 | }); | ||
| 1840 | } | ||
| 1841 | |||
| 1842 |
2/2✓ Branch 0 taken 15545021 times.
✓ Branch 1 taken 1722 times.
|
15546743 | if (!error) thd->diff_commit_trans++; |
| 1843 | |||
| 1844 | 15546743 | return error; | |
| 1845 | 15546744 | } | |
| 1846 | |||
| 1847 | /** | ||
| 1848 | Commit the sessions outstanding transaction. | ||
| 1849 | |||
| 1850 | @pre thd->transaction.flags.commit_low == true | ||
| 1851 | @post thd->transaction.flags.commit_low == false | ||
| 1852 | |||
| 1853 | @note This function does not care about global read lock; the caller | ||
| 1854 | should. | ||
| 1855 | |||
| 1856 | @param[in] thd Thread handle. | ||
| 1857 | @param[in] all Is set in case of explicit commit | ||
| 1858 | (COMMIT statement), or implicit commit | ||
| 1859 | issued by DDL. Is not set when called | ||
| 1860 | at the end of statement, even if | ||
| 1861 | autocommit=1. | ||
| 1862 | @param[in] run_after_commit | ||
| 1863 | True by default, otherwise, does not execute | ||
| 1864 | the after_commit hook in the function. | ||
| 1865 | */ | ||
| 1866 | |||
| 1867 | 26412910 | int ha_commit_low(THD *thd, bool all, bool run_after_commit) { | |
| 1868 | 26412910 | int error = 0; | |
| 1869 | 26412910 | Transaction_ctx *trn_ctx = thd->get_transaction(); | |
| 1870 | 26413543 | Transaction_ctx::enum_trx_scope trx_scope = | |
| 1871 |
2/2✓ Branch 0 taken 6014804 times.
✓ Branch 1 taken 20398739 times.
|
26413543 | all ? Transaction_ctx::SESSION : Transaction_ctx::STMT; |
| 1872 |
1/2✓ Branch 0 taken 26412879 times.
✗ Branch 1 not taken.
|
26413543 | auto ha_list = trn_ctx->ha_trx_info(trx_scope); |
| 1873 | |||
| 1874 |
1/2✓ Branch 0 taken 26415341 times.
✗ Branch 1 not taken.
|
26412879 | DBUG_TRACE; |
| 1875 | |||
| 1876 | #ifdef WITH_WSREP | ||
| 1877 |
5/8✓ Branch 0 taken 52098 times.
✓ Branch 1 taken 26363243 times.
✓ Branch 2 taken 52098 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 52098 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 26415341 times.
|
26415341 | if (thd->run_wsrep_commit_hooks && wsrep_before_commit(thd, all)) { |
| 1878 | ✗ | thd->run_wsrep_commit_hooks = false; | |
| 1879 | ✗ | return 1; | |
| 1880 | } | ||
| 1881 | #endif /* WITH_WSREP */ | ||
| 1882 | |||
| 1883 |
3/4✓ Branch 0 taken 26415133 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13616222 times.
✓ Branch 3 taken 12798911 times.
|
26415341 | if (ha_list) { |
| 1884 | 12798911 | bool restore_backup_ha_data = false; | |
| 1885 | /* | ||
| 1886 | At execution of XA COMMIT ONE PHASE binlog or slave applier | ||
| 1887 | reattaches the engine ha_data to THD, previously saved at XA START. | ||
| 1888 | */ | ||
| 1889 |
7/8✓ Branch 0 taken 1233417 times.
✓ Branch 1 taken 11565494 times.
✓ Branch 2 taken 1233403 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
✓ Branch 5 taken 1233348 times.
✓ Branch 6 taken 55 times.
✓ Branch 7 taken 12798842 times.
|
12798911 | if (all && thd->is_engine_ha_data_detached()) { |
| 1890 |
3/10✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 55 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
55 | DBUG_PRINT("info", ("query='%s'", thd->query().str)); |
| 1891 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | assert(thd->lex->sql_command == SQLCOM_XA_COMMIT); |
| 1892 |
2/4✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 55 times.
|
55 | assert( |
| 1893 | static_cast<Sql_cmd_xa_commit *>(thd->lex->m_sql_cmd)->get_xa_opt() == | ||
| 1894 | XA_ONE_PHASE); | ||
| 1895 | 55 | restore_backup_ha_data = true; | |
| 1896 | } | ||
| 1897 | |||
| 1898 | 12798897 | bool is_applier_wait_enabled = false; | |
| 1899 | |||
| 1900 | /* | ||
| 1901 | Preserve externalization and persistence order for applier threads. | ||
| 1902 | |||
| 1903 | The conditions should be understood as follows: | ||
| 1904 | |||
| 1905 | - When the binlog is enabled, this will be done from | ||
| 1906 | MYSQL_BIN_LOG::ordered_commit and should not be done here. | ||
| 1907 | Therefore, we have the condition | ||
| 1908 | thd->is_current_stmt_binlog_disabled(). | ||
| 1909 | |||
| 1910 | - This function is usually called once per statement, with | ||
| 1911 | all=false. We should not preserve the commit order when this | ||
| 1912 | function is called in that context. Therefore, we have the | ||
| 1913 | condition ending_trans(thd, all). | ||
| 1914 | |||
| 1915 | - Statements such as ANALYZE/OPTIMIZE/REPAIR TABLE will call | ||
| 1916 | ha_commit_low multiple times with all=true from within | ||
| 1917 | mysql_admin_table, mysql_recreate_table, and | ||
| 1918 | handle_histogram_command. After returning to | ||
| 1919 | mysql_execute_command, it will call ha_commit_low one last | ||
| 1920 | time. It is only in this final call that we should preserve | ||
| 1921 | the commit order. Therefore, we set the flag | ||
| 1922 | thd->is_operating_substatement_implicitly while executing | ||
| 1923 | mysql_admin_table, mysql_recreate_table, and | ||
| 1924 | handle_histogram_command, clear it when returning from those | ||
| 1925 | functions, and check the flag here in ha_commit_low(). | ||
| 1926 | |||
| 1927 | - In all the above cases, we should make the current transaction | ||
| 1928 | fail early in case a previous transaction has rolled back. | ||
| 1929 | Therefore, we also invoke the commit order manager in case | ||
| 1930 | get_rollback_status returns true. | ||
| 1931 | |||
| 1932 | Note: the calls to Commit_order_manager::wait/wait_and_finish() will be | ||
| 1933 | no-op for threads other than replication applier threads. | ||
| 1934 | */ | ||
| 1935 | 37399212 | if ((!thd->is_operating_substatement_implicitly && | |
| 1936 |
2/2✓ Branch 0 taken 11637228 times.
✓ Branch 1 taken 164202 times.
|
11801430 | !thd->is_operating_gtid_table_implicitly && |
| 1937 |
3/4✓ Branch 0 taken 11637256 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4237982 times.
✓ Branch 3 taken 7399274 times.
|
11637228 | thd->is_current_stmt_binlog_log_replica_updates_disabled() && |
| 1938 |
7/8✓ Branch 0 taken 11801430 times.
✓ Branch 1 taken 997467 times.
✓ Branch 2 taken 4237982 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3885348 times.
✓ Branch 5 taken 352634 times.
✓ Branch 6 taken 352701 times.
✓ Branch 7 taken 12446184 times.
|
29483130 | ending_trans(thd, all)) || |
| 1939 |
3/4✓ Branch 0 taken 12446251 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 12446184 times.
|
12446291 | Commit_order_manager::get_rollback_status(thd)) { |
| 1940 |
3/4✓ Branch 0 taken 352701 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
✓ Branch 3 taken 352631 times.
|
352701 | if (Commit_order_manager::wait(thd)) { |
| 1941 | 70 | error = 1; | |
| 1942 | /* | ||
| 1943 | Remove applier thread from waiting in Commit Order Queue and | ||
| 1944 | allow next applier thread to be ordered. | ||
| 1945 | */ | ||
| 1946 |
1/2✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
|
70 | Commit_order_manager::wait_and_finish(thd, error); |
| 1947 | 70 | goto err; | |
| 1948 | } | ||
| 1949 | 352631 | is_applier_wait_enabled = true; | |
| 1950 | } | ||
| 1951 | |||
| 1952 |
7/12✓ Branch 0 taken 12798845 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12798856 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17777075 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17776834 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 30575666 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 17777067 times.
✓ Branch 11 taken 12798599 times.
|
30575878 | for (auto &ha_info : ha_list) { |
| 1953 | int err; | ||
| 1954 | 17777075 | auto ht = ha_info.ht(); | |
| 1955 |
3/4✓ Branch 0 taken 17776919 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 17776915 times.
|
17777085 | if ((err = ht->commit(ht, thd, all))) { |
| 1956 | char errbuf[MYSQL_ERRMSG_SIZE]; | ||
| 1957 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | my_error(ER_ERROR_DURING_COMMIT, MYF(0), err, |
| 1958 | my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); | ||
| 1959 | 4 | error = 1; | |
| 1960 | } | ||
| 1961 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17776919 times.
|
17776919 | assert(!thd->status_var_aggregated); |
| 1962 | 17776919 | thd->status_var.ha_commit_count++; | |
| 1963 |
1/2✓ Branch 0 taken 17777063 times.
✗ Branch 1 not taken.
|
17776919 | ha_info.reset(); /* keep it conveniently zero-filled */ |
| 1964 | 12798599 | } | |
| 1965 |
3/4✓ Branch 0 taken 55 times.
✓ Branch 1 taken 12798545 times.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
|
12798600 | if (restore_backup_ha_data) thd->rpl_reattach_engine_ha_data(); |
| 1966 |
1/2✓ Branch 0 taken 12798791 times.
✗ Branch 1 not taken.
|
12798600 | trn_ctx->reset_scope(trx_scope); |
| 1967 | |||
| 1968 | /* | ||
| 1969 | After ensuring externalization order for applier thread, remove it | ||
| 1970 | from waiting (Commit Order Queue) and allow next applier thread to | ||
| 1971 | be ordered. | ||
| 1972 | |||
| 1973 | Note: the calls to Commit_order_manager::wait_and_finish() will be | ||
| 1974 | no-op for threads other than replication applier threads. | ||
| 1975 | */ | ||
| 1976 |
2/2✓ Branch 0 taken 352630 times.
✓ Branch 1 taken 12446161 times.
|
12798791 | if (is_applier_wait_enabled) { |
| 1977 |
1/2✓ Branch 0 taken 352621 times.
✗ Branch 1 not taken.
|
352630 | Commit_order_manager::wait_and_finish(thd, error); |
| 1978 | } | ||
| 1979 | } | ||
| 1980 | |||
| 1981 | 13616222 | err: | |
| 1982 | /* Free resources and perform other cleanup even for 'empty' transactions. */ | ||
| 1983 |
3/4✓ Branch 0 taken 6015007 times.
✓ Branch 1 taken 20400067 times.
✓ Branch 2 taken 6015003 times.
✗ Branch 3 not taken.
|
26415074 | if (all) trn_ctx->cleanup(); |
| 1984 | /* | ||
| 1985 | When the transaction has been committed, we clear the commit_low | ||
| 1986 | flag. This allow other parts of the system to check if commit_low | ||
| 1987 | was called. | ||
| 1988 | */ | ||
| 1989 | 26415070 | trn_ctx->m_flags.commit_low = false; | |
| 1990 |
6/6✓ Branch 0 taken 23831754 times.
✓ Branch 1 taken 2583316 times.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 23831548 times.
✓ Branch 4 taken 83 times.
✓ Branch 5 taken 26414864 times.
|
26415070 | if (run_after_commit && thd->get_transaction()->m_flags.run_hooks) { |
| 1991 | /* | ||
| 1992 | If commit succeeded, we call the after_commit hook. | ||
| 1993 | |||
| 1994 | TODO: Investigate if this can be refactored so that there is | ||
| 1995 | only one invocation of this hook in the code (in | ||
| 1996 | MYSQL_LOG_BIN::finish_commit). | ||
| 1997 | */ | ||
| 1998 |
3/8✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 83 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
83 | if (!error) (void)RUN_HOOK(transaction, after_commit, (thd, all)); |
| 1999 | 83 | trn_ctx->m_flags.run_hooks = false; | |
| 2000 | } | ||
| 2001 | |||
| 2002 | #ifdef WITH_WSREP | ||
| 2003 |
4/4✓ Branch 0 taken 26414702 times.
✓ Branch 1 taken 245 times.
✓ Branch 2 taken 52098 times.
✓ Branch 3 taken 26362604 times.
|
26414947 | if (!error && thd->run_wsrep_commit_hooks) { |
| 2004 |
1/2✓ Branch 0 taken 52015 times.
✗ Branch 1 not taken.
|
52098 | (void)wsrep_after_commit(thd, all); |
| 2005 | } | ||
| 2006 | 26414864 | thd->run_wsrep_commit_hooks = false; | |
| 2007 | #endif /* WITH_WSREP */ | ||
| 2008 | |||
| 2009 | 26414864 | return error; | |
| 2010 | 26414864 | } | |
| 2011 | |||
| 2012 | 2105898 | int ha_rollback_low(THD *thd, bool all) { | |
| 2013 | 2105898 | Transaction_ctx *trn_ctx = thd->get_transaction(); | |
| 2014 | 2106237 | int error = 0; | |
| 2015 | 2106237 | Transaction_ctx::enum_trx_scope trx_scope = | |
| 2016 |
2/2✓ Branch 0 taken 1193719 times.
✓ Branch 1 taken 912518 times.
|
2106237 | all ? Transaction_ctx::SESSION : Transaction_ctx::STMT; |
| 2017 |
1/2✓ Branch 0 taken 2105661 times.
✗ Branch 1 not taken.
|
2106237 | auto ha_list = trn_ctx->ha_trx_info(trx_scope); |
| 2018 | |||
| 2019 |
4/6✓ Branch 0 taken 2105046 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 336905 times.
✓ Branch 3 taken 1768141 times.
✓ Branch 4 taken 337524 times.
✗ Branch 5 not taken.
|
2105661 | (void)RUN_HOOK(transaction, before_rollback, (thd, all)); |
| 2020 | |||
| 2021 | #ifdef WITH_WSREP | ||
| 2022 |
1/2✓ Branch 0 taken 2107249 times.
✗ Branch 1 not taken.
|
2105665 | (void)wsrep_before_rollback(thd, all); |
| 2023 | #endif /* WITH_WSREP */ | ||
| 2024 | |||
| 2025 |
3/4✓ Branch 0 taken 2107055 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 647414 times.
✓ Branch 3 taken 1459641 times.
|
2107249 | if (ha_list) { |
| 2026 | 647414 | bool restore_backup_ha_data = false; | |
| 2027 | /* | ||
| 2028 | Similarly to the commit case, the binlog or slave applier | ||
| 2029 | reattaches the engine ha_data to THD. | ||
| 2030 | */ | ||
| 2031 |
7/8✓ Branch 0 taken 10480 times.
✓ Branch 1 taken 636934 times.
✓ Branch 2 taken 10481 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 10460 times.
✓ Branch 6 taken 21 times.
✓ Branch 7 taken 647394 times.
|
647414 | if (all && thd->is_engine_ha_data_detached()) { |
| 2032 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
21 | assert(trn_ctx->xid_state()->get_state() != XID_STATE::XA_NOTR || |
| 2033 | thd->killed == THD::KILL_CONNECTION); | ||
| 2034 | |||
| 2035 | 21 | restore_backup_ha_data = true; | |
| 2036 | } | ||
| 2037 | |||
| 2038 |
7/12✓ Branch 0 taken 647416 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 647416 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 654610 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 654602 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1302014 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 654610 times.
✓ Branch 11 taken 647404 times.
|
1302018 | for (auto &ha_info : ha_list) { |
| 2039 | int err; | ||
| 2040 | 654610 | auto ht = ha_info.ht(); | |
| 2041 |
2/4✓ Branch 0 taken 654600 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 654600 times.
|
654614 | if ((err = ht->rollback(ht, thd, all))) { // cannot happen |
| 2042 | |||
| 2043 | #ifdef WITH_WSREP | ||
| 2044 | ✗ | WSREP_INFO( | |
| 2045 | "rollback failed for handlerton: %d, conflict-state: %s SQL %s", | ||
| 2046 | ht->db_type, wsrep_thd_transaction_state_str(thd), | ||
| 2047 | thd->query().str); | ||
| 2048 | ✗ | Diagnostics_area *da = thd->get_stmt_da(); | |
| 2049 | ✗ | if (da) { | |
| 2050 | ✗ | WSREP_INFO("stmt DA %d %s", da->status(), | |
| 2051 | (da->is_error()) ? da->message_text() : "void"); | ||
| 2052 | } | ||
| 2053 | #endif /* WITH_WSREP */ | ||
| 2054 | |||
| 2055 | char errbuf[MYSQL_ERRMSG_SIZE]; | ||
| 2056 | ✗ | my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err, | |
| 2057 | my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); | ||
| 2058 | ✗ | error = 1; | |
| 2059 | } | ||
| 2060 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 654600 times.
|
654600 | assert(!thd->status_var_aggregated); |
| 2061 | 654600 | thd->status_var.ha_rollback_count++; | |
| 2062 |
1/2✓ Branch 0 taken 654603 times.
✗ Branch 1 not taken.
|
654600 | ha_info.reset(); /* keep it conveniently zero-filled */ |
| 2063 | 647404 | } | |
| 2064 |
3/4✓ Branch 0 taken 21 times.
✓ Branch 1 taken 647383 times.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
|
647404 | if (restore_backup_ha_data) thd->rpl_reattach_engine_ha_data(); |
| 2065 |
1/2✓ Branch 0 taken 647181 times.
✗ Branch 1 not taken.
|
647404 | trn_ctx->reset_scope(trx_scope); |
| 2066 | } | ||
| 2067 | |||
| 2068 | /* | ||
| 2069 | Thanks to possibility of MDL deadlock rollback request can come even if | ||
| 2070 | transaction hasn't been started in any transactional storage engine. | ||
| 2071 | |||
| 2072 | It is possible to have a call of ha_rollback_low() while handling | ||
| 2073 | failure from Sql_cmd_xa_prepare::process_xa_prepare() and an error in | ||
| 2074 | Daignostics_area still wasn't set. Therefore it is required to check | ||
| 2075 | that an error in Diagnostics_area is set before calling the method | ||
| 2076 | XID_STATE::set_error(). | ||
| 2077 | |||
| 2078 | If it wasn't done it would lead to failure of the assertion | ||
| 2079 | assert(m_status == DA_ERROR) | ||
| 2080 | in the method Diagnostics_area::mysql_errno(). | ||
| 2081 | |||
| 2082 | In case Sql_cmd_xa_prepare::process_xa_prepare() has failed and an error | ||
| 2083 | wasn't set in Diagnostics_area the error ER_XA_RBROLLBACK is set in the | ||
| 2084 | Diagnostics_area from the method Sql_cmd_xa_prepare::trans_xa_prepare() | ||
| 2085 | when non-zero result code returned by | ||
| 2086 | Sql_cmd_xa_prepare::process_xa_prepare() is handled. | ||
| 2087 | */ | ||
| 2088 |
9/10✓ Branch 0 taken 1193851 times.
✓ Branch 1 taken 912971 times.
✓ Branch 2 taken 512 times.
✓ Branch 3 taken 1193339 times.
✓ Branch 4 taken 512 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 508 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 508 times.
✓ Branch 9 taken 2106314 times.
|
2106822 | if (all && thd->transaction_rollback_request && thd->is_error()) |
| 2089 |
1/2✓ Branch 0 taken 508 times.
✗ Branch 1 not taken.
|
508 | trn_ctx->xid_state()->set_error(thd); |
| 2090 | |||
| 2091 | #ifdef WITH_WSREP | ||
| 2092 |
3/4✓ Branch 0 taken 2107483 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 251624 times.
✓ Branch 3 taken 1855859 times.
|
2106822 | if (thd->is_error()) { |
| 2093 |
23/42✓ Branch 0 taken 1831 times.
✓ Branch 1 taken 249793 times.
✓ Branch 2 taken 1831 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1831 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1831 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1831 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1831 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1831 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1831 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1831 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1831 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1831 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 3 times.
✓ Branch 23 taken 1828 times.
✓ Branch 24 taken 3 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 3 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1828 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 7 times.
✓ Branch 31 taken 1824 times.
✓ Branch 32 taken 1831 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 3 times.
✓ Branch 35 taken 1828 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 1831 times.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
|
251624 | WSREP_DEBUG("ha_rollback_trans(%u, %s) rolled back: %s: XX%s;", |
| 2094 | thd->thread_id(), all ? "TRUE" : "FALSE", WSREP_QUERY(thd), | ||
| 2095 | thd->get_stmt_da()->message_text()); | ||
| 2096 |
9/10✓ Branch 0 taken 251618 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 46221 times.
✓ Branch 3 taken 205397 times.
✓ Branch 4 taken 11112 times.
✓ Branch 5 taken 35109 times.
✓ Branch 6 taken 10198 times.
✓ Branch 7 taken 914 times.
✓ Branch 8 taken 10198 times.
✗ Branch 9 not taken.
|
251624 | WSREP_NBO_1ST_PHASE_END; |
| 2097 | } | ||
| 2098 |
1/2✓ Branch 0 taken 2106661 times.
✗ Branch 1 not taken.
|
2107483 | (void)wsrep_after_rollback(thd, all); |
| 2099 | #endif /* WITH_WSREP */ | ||
| 2100 | |||
| 2101 |
4/6✓ Branch 0 taken 2106774 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 337437 times.
✓ Branch 3 taken 1769337 times.
✓ Branch 4 taken 337560 times.
✗ Branch 5 not taken.
|
2106661 | (void)RUN_HOOK(transaction, after_rollback, (thd, all)); |
| 2102 | 2106112 | return error; | |
| 2103 | 2106897 | } | |
| 2104 | |||
| 2105 | 1869534 | int ha_rollback_trans(THD *thd, bool all) { | |
| 2106 | 1869534 | int error = 0; | |
| 2107 | 1869534 | Transaction_ctx *trn_ctx = thd->get_transaction(); | |
| 2108 | 1870085 | bool is_xa_rollback = trn_ctx->xid_state()->has_state(XID_STATE::XA_PREPARED); | |
| 2109 | |||
| 2110 | /* | ||
| 2111 | "real" is a nick name for a transaction for which a commit will | ||
| 2112 | make persistent changes. E.g. a 'stmt' transaction inside a 'all' | ||
| 2113 | transaction is not 'real': even though it's possible to commit it, | ||
| 2114 | the changes are not durable as they might be rolled back if the | ||
| 2115 | enclosing 'all' transaction is rolled back. | ||
| 2116 | We establish the value of 'is_real_trans' by checking | ||
| 2117 | if it's an explicit COMMIT or BEGIN statement, or implicit | ||
| 2118 | commit issued by DDL (in these cases all == true), | ||
| 2119 | or if we're running in autocommit mode (it's only in the autocommit mode | ||
| 2120 | ha_commit_one_phase() is called with an empty | ||
| 2121 | transaction.all.ha_list, see why in trans_register_ha()). | ||
| 2122 | */ | ||
| 2123 |
4/4✓ Branch 0 taken 636941 times.
✓ Branch 1 taken 1233183 times.
✓ Branch 2 taken 629450 times.
✓ Branch 3 taken 7491 times.
|
1870124 | bool is_real_trans = all || !trn_ctx->is_active(Transaction_ctx::SESSION); |
| 2124 | |||
| 2125 |
1/2✓ Branch 0 taken 1870304 times.
✗ Branch 1 not taken.
|
1870124 | DBUG_TRACE; |
| 2126 | |||
| 2127 | /* | ||
| 2128 | We must not rollback the normal transaction if a statement | ||
| 2129 | transaction is pending. | ||
| 2130 | */ | ||
| 2131 |
3/4✓ Branch 0 taken 636092 times.
✓ Branch 1 taken 1234480 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 636092 times.
|
1870304 | assert(!trn_ctx->is_active(Transaction_ctx::STMT) || !all); |
| 2132 | |||
| 2133 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1870572 times.
|
1870572 | if (thd->in_sub_stmt) { |
| 2134 | ✗ | assert(0); | |
| 2135 | /* | ||
| 2136 | If we are inside stored function or trigger we should not commit or | ||
| 2137 | rollback current statement transaction. See comment in ha_commit_trans() | ||
| 2138 | call for more information. | ||
| 2139 | */ | ||
| 2140 | if (!all) return 0; | ||
| 2141 | my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); | ||
| 2142 | return 1; | ||
| 2143 | } | ||
| 2144 | |||
| 2145 |
3/4✓ Branch 0 taken 1831474 times.
✓ Branch 1 taken 39098 times.
✓ Branch 2 taken 1830997 times.
✗ Branch 3 not taken.
|
1870572 | if (tc_log) error = tc_log->rollback(thd, all); |
| 2146 | /* | ||
| 2147 | Mark multi-statement (any autocommit mode) or single-statement | ||
| 2148 | (autocommit=1) transaction as rolled back | ||
| 2149 | */ | ||
| 2150 | #ifdef HAVE_PSI_TRANSACTION_INTERFACE | ||
| 2151 |
6/6✓ Branch 0 taken 636942 times.
✓ Branch 1 taken 1233153 times.
✓ Branch 2 taken 629239 times.
✓ Branch 3 taken 7703 times.
✓ Branch 4 taken 1862522 times.
✓ Branch 5 taken 7573 times.
|
1870095 | if (all || !thd->in_active_multi_stmt_transaction()) { |
| 2152 |
1/2✓ Branch 0 taken 1862383 times.
✗ Branch 1 not taken.
|
1862522 | MYSQL_ROLLBACK_TRANSACTION(thd->m_transaction_psi); |
| 2153 | 1862383 | thd->m_transaction_psi = nullptr; | |
| 2154 | } | ||
| 2155 | #endif | ||
| 2156 | |||
| 2157 | 1869956 | thd->diff_rollback_trans++; | |
| 2158 | |||
| 2159 | /* Always cleanup. Even if nht==0. There may be savepoints. */ | ||
| 2160 |
2/2✓ Branch 0 taken 1862848 times.
✓ Branch 1 taken 7108 times.
|
1869956 | if (is_real_trans) { |
| 2161 |
1/2✓ Branch 0 taken 1862875 times.
✗ Branch 1 not taken.
|
1862848 | trn_ctx->cleanup(); |
| 2162 | 1862875 | thd->tx_priority = 0; | |
| 2163 | } | ||
| 2164 | |||
| 2165 |
2/2✓ Branch 0 taken 1233395 times.
✓ Branch 1 taken 636588 times.
|
1869983 | if (all) thd->transaction_rollback_request = false; |
| 2166 | |||
| 2167 | /* | ||
| 2168 | Only call gtid_rollback(THD*), which will purge thd->owned_gtid, if | ||
| 2169 | complete transaction is being rollback or autocommit=1. | ||
| 2170 | Notice, XA rollback has just invoked update_on_commit() through | ||
| 2171 | tc_log->*rollback* stack. | ||
| 2172 | */ | ||
| 2173 |
4/6✓ Branch 0 taken 1862918 times.
✓ Branch 1 taken 7065 times.
✓ Branch 2 taken 1862986 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1863420 times.
✗ Branch 5 not taken.
|
1869983 | if (is_real_trans && !is_xa_rollback) gtid_state->update_on_rollback(thd); |
| 2174 | |||
| 2175 | /* | ||
| 2176 | If the transaction cannot be rolled back safely, warn; don't warn if this | ||
| 2177 | is a slave thread (because when a slave thread executes a ROLLBACK, it has | ||
| 2178 | been read from the binary log, so it's 100% sure and normal to produce | ||
| 2179 | error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the | ||
| 2180 | slave SQL thread, it would not stop the thread but just be printed in | ||
| 2181 | the error log; but we don't want users to wonder why they have this | ||
| 2182 | message in the error log, so we don't send it. | ||
| 2183 | */ | ||
| 2184 |
2/2✓ Branch 0 taken 3531 times.
✓ Branch 1 taken 1859501 times.
|
1863032 | if (is_real_trans && |
| 2185 | 1863205 | trn_ctx->cannot_safely_rollback(Transaction_ctx::SESSION) && | |
| 2186 |
8/8✓ Branch 0 taken 1863205 times.
✓ Branch 1 taken 7212 times.
✓ Branch 2 taken 3344 times.
✓ Branch 3 taken 187 times.
✓ Branch 4 taken 2834 times.
✓ Branch 5 taken 510 times.
✓ Branch 6 taken 2834 times.
✓ Branch 7 taken 1867410 times.
|
3733449 | !thd->slave_thread && thd->killed != THD::KILL_CONNECTION) |
| 2187 |
1/2✓ Branch 0 taken 2834 times.
✗ Branch 1 not taken.
|
2834 | trn_ctx->push_unsafe_rollback_warnings(thd); |
| 2188 | |||
| 2189 | 1870244 | return error; | |
| 2190 | 1870244 | } | |
| 2191 | |||
| 2192 | /** | ||
| 2193 | Commit the attachable transaction in storage engines. | ||
| 2194 | |||
| 2195 | @note This is slimmed down version of ha_commit_trans()/ha_commit_low() | ||
| 2196 | which commits attachable transaction but skips code which is | ||
| 2197 | unnecessary and unsafe for them (like dealing with GTIDs). | ||
| 2198 | Since attachable transactions are read-only their commit only | ||
| 2199 | needs to release resources and cleanup state in SE. | ||
| 2200 | |||
| 2201 | @param thd Current thread | ||
| 2202 | |||
| 2203 | @retval 0 - Success | ||
| 2204 | @retval non-0 - Failure | ||
| 2205 | */ | ||
| 2206 | 15218298 | int ha_commit_attachable(THD *thd) { | |
| 2207 | 15218298 | int error = 0; | |
| 2208 | 15218298 | Transaction_ctx *trn_ctx = thd->get_transaction(); | |
| 2209 |
1/2✓ Branch 0 taken 15218314 times.
✗ Branch 1 not taken.
|
15218318 | auto ha_list = trn_ctx->ha_trx_info(Transaction_ctx::STMT); |
| 2210 | |||
| 2211 | /* This function only handles attachable transactions. */ | ||
| 2212 |
2/4✓ Branch 0 taken 15218325 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15218325 times.
|
15218314 | assert(thd->is_attachable_ro_transaction_active()); |
| 2213 | /* | ||
| 2214 | Since the attachable transaction is AUTOCOMMIT we only need | ||
| 2215 | to care about statement transaction. | ||
| 2216 | */ | ||
| 2217 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15218325 times.
|
15218325 | assert(!trn_ctx->is_active(Transaction_ctx::SESSION)); |
| 2218 | |||
| 2219 |
2/4✓ Branch 0 taken 15218307 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15218310 times.
✗ Branch 3 not taken.
|
15218325 | if (ha_list) { |
| 2220 |
7/12✓ Branch 0 taken 15218323 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15218326 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15218300 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15218327 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 30436623 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 15218301 times.
✓ Branch 11 taken 15218322 times.
|
30436639 | for (auto &ha_info : ha_list) { |
| 2221 | /* Attachable transaction is not supposed to modify anything. */ | ||
| 2222 |
2/4✓ Branch 0 taken 15218321 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15218321 times.
|
15218300 | assert(!ha_info.is_trx_read_write()); |
| 2223 | |||
| 2224 | 15218321 | auto ht = ha_info.ht(); | |
| 2225 |
2/4✓ Branch 0 taken 15218325 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15218325 times.
|
15218326 | if (ht->commit(ht, thd, false)) { |
| 2226 | /* | ||
| 2227 | In theory this should not happen since attachable transactions | ||
| 2228 | are read only and therefore commit is supposed to only release | ||
| 2229 | resources/cleanup state. Even if this happens we will simply | ||
| 2230 | continue committing attachable transaction in other SEs. | ||
| 2231 | */ | ||
| 2232 | ✗ | assert(false); | |
| 2233 | error = 1; | ||
| 2234 | } | ||
| 2235 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15218325 times.
|
15218325 | assert(!thd->status_var_aggregated); |
| 2236 | 15218325 | thd->status_var.ha_commit_count++; | |
| 2237 |
1/2✓ Branch 0 taken 15218329 times.
✗ Branch 1 not taken.
|
15218325 | ha_info.reset(); /* keep it conveniently zero-filled */ |
| 2238 | 15218322 | } | |
| 2239 |
1/2✓ Branch 0 taken 15218333 times.
✗ Branch 1 not taken.
|
15218315 | trn_ctx->reset_scope(Transaction_ctx::STMT); |
| 2240 | } | ||
| 2241 | |||
| 2242 | /* | ||
| 2243 | Mark transaction as committed in PSI. | ||
| 2244 | */ | ||
| 2245 | #ifdef HAVE_PSI_TRANSACTION_INTERFACE | ||
| 2246 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15218330 times.
|
15218330 | if (thd->m_transaction_psi != nullptr) { |
| 2247 | ✗ | MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi); | |
| 2248 | ✗ | thd->m_transaction_psi = nullptr; | |
| 2249 | } | ||
| 2250 | #endif | ||
| 2251 | |||
| 2252 | /* Free resources and perform other cleanup even for 'empty' transactions. */ | ||
| 2253 |
1/2✓ Branch 0 taken 15218328 times.
✗ Branch 1 not taken.
|
15218330 | trn_ctx->cleanup(); |
| 2254 | |||
| 2255 | 15218326 | return (error); | |
| 2256 | 15218328 | } | |
| 2257 | |||
| 2258 | /** | ||
| 2259 | Check if all storage engines used in transaction agree that after | ||
| 2260 | rollback to savepoint it is safe to release MDL locks acquired after | ||
| 2261 | savepoint creation. | ||
| 2262 | |||
| 2263 | @param thd The client thread that executes the transaction. | ||
| 2264 | |||
| 2265 | @return true - It is safe to release MDL locks. | ||
| 2266 | false - If it is not. | ||
| 2267 | */ | ||
| 2268 | 4265 | bool ha_rollback_to_savepoint_can_release_mdl(THD *thd) { | |
| 2269 | 4265 | Transaction_ctx *trn_ctx = thd->get_transaction(); | |
| 2270 | 4265 | Transaction_ctx::enum_trx_scope trx_scope = | |
| 2271 | 4265 | thd->in_sub_stmt ? Transaction_ctx::STMT : Transaction_ctx::SESSION; | |
| 2272 | |||
| 2273 |
1/2✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
|
4265 | DBUG_TRACE; |
| 2274 | |||
| 2275 | /** | ||
| 2276 | Checking whether it is safe to release metadata locks after rollback to | ||
| 2277 | savepoint in all the storage engines that are part of the transaction. | ||
| 2278 | */ | ||
| 2279 |
8/14✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4265 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4265 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8250 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4227 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8492 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 8250 times.
✓ Branch 13 taken 242 times.
|
8492 | for (auto const &ha_info : trn_ctx->ha_trx_info(trx_scope)) { |
| 2280 | 8250 | auto ht = ha_info.ht(); | |
| 2281 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8250 times.
|
8250 | assert(ht); |
| 2282 | |||
| 2283 |
3/4✓ Branch 0 taken 8250 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4023 times.
✓ Branch 3 taken 4227 times.
|
16500 | if (ht->savepoint_rollback_can_release_mdl == nullptr || |
| 2284 |
3/4✓ Branch 0 taken 8250 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4023 times.
✓ Branch 3 taken 4227 times.
|
8250 | ht->savepoint_rollback_can_release_mdl(ht, thd) == false) |
| 2285 | 4023 | return false; | |
| 2286 |
6/6✓ Branch 0 taken 242 times.
✓ Branch 1 taken 4023 times.
✓ Branch 2 taken 242 times.
✓ Branch 3 taken 4023 times.
✓ Branch 4 taken 242 times.
✓ Branch 5 taken 4023 times.
|
12311 | } |
| 2287 | |||
| 2288 | 242 | return true; | |
| 2289 | 4265 | } | |
| 2290 | |||
| 2291 | 4265 | int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) { | |
| 2292 | 4265 | int error = 0; | |
| 2293 | 4265 | Transaction_ctx *trn_ctx = thd->get_transaction(); | |
| 2294 | 4265 | Transaction_ctx::enum_trx_scope trx_scope = | |
| 2295 |
2/2✓ Branch 0 taken 4228 times.
✓ Branch 1 taken 37 times.
|
4265 | !thd->in_sub_stmt ? Transaction_ctx::SESSION : Transaction_ctx::STMT; |
| 2296 | |||
| 2297 |
1/2✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
|
4265 | DBUG_TRACE; |
| 2298 | |||
| 2299 | 4265 | trn_ctx->set_rw_ha_count(trx_scope, 0); | |
| 2300 | 4265 | trn_ctx->set_no_2pc(trx_scope, false); | |
| 2301 | /* | ||
| 2302 | rolling back to savepoint in all storage engines that were part of the | ||
| 2303 | transaction when the savepoint was set | ||
| 2304 | */ | ||
| 2305 |
1/2✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
|
4265 | Ha_trx_info_list ha_list{sv->ha_list}; |
| 2306 |
7/12✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4265 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8272 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8272 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12537 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8272 times.
✓ Branch 11 taken 4265 times.
|
12537 | for (auto const &ha_info : ha_list) { |
| 2307 | int err; | ||
| 2308 | 8272 | auto ht = ha_info.ht(); | |
| 2309 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8272 times.
|
8272 | assert(ht); |
| 2310 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8272 times.
|
8272 | assert(ht->savepoint_set != nullptr); |
| 2311 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8272 times.
|
8272 | if ((err = ht->savepoint_rollback( |
| 2312 | ht, thd, | ||
| 2313 |
1/2✓ Branch 0 taken 8272 times.
✗ Branch 1 not taken.
|
8272 | (uchar *)(sv + 1) + ht->savepoint_offset))) { // cannot happen |
| 2314 | char errbuf[MYSQL_ERRMSG_SIZE]; | ||
| 2315 | ✗ | my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err, | |
| 2316 | my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); | ||
| 2317 | ✗ | error = 1; | |
| 2318 | } | ||
| 2319 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8272 times.
|
8272 | assert(!thd->status_var_aggregated); |
| 2320 | 8272 | thd->status_var.ha_savepoint_rollback_count++; | |
| 2321 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8272 times.
|
8272 | if (ht->prepare == nullptr) trn_ctx->set_no_2pc(trx_scope, true); |
| 2322 | 4265 | } | |
| 2323 | |||
| 2324 | /* | ||
| 2325 | rolling back the transaction in all storage engines that were not part of | ||
| 2326 | the transaction when the savepoint was set | ||
| 2327 | */ | ||
| 2328 |
2/4✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4265 times.
✗ Branch 3 not taken.
|
4265 | ha_list = trn_ctx->ha_trx_info(trx_scope); |
| 2329 |
5/8✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4335 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 70 times.
✓ Branch 7 taken 4265 times.
|
4335 | for (auto ha_info = ha_list.begin(); ha_info != sv->ha_list; ++ha_info) { |
| 2330 | int err; | ||
| 2331 |
1/2✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
|
70 | auto *ht = ha_info->ht(); |
| 2332 | |||
| 2333 | #ifdef WITH_WSREP | ||
| 2334 |
7/10✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 62 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 4 times.
|
70 | if (WSREP(thd) && (ht->flags & HTON_WSREP_REPLICATION)) { |
| 2335 |
1/24✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
4 | WSREP_DEBUG( |
| 2336 | "ha_rollback_to_savepoint: run before_rollback" | ||
| 2337 | " ha_rollback_trans hook"); | ||
| 2338 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | (void)wsrep_before_rollback(thd, !thd->in_sub_stmt); |
| 2339 | } | ||
| 2340 | #endif /* WITH_WSREP */ | ||
| 2341 | |||
| 2342 |
2/4✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 70 times.
|
70 | if ((err = ht->rollback(ht, thd, !thd->in_sub_stmt))) { // cannot happen |
| 2343 | char errbuf[MYSQL_ERRMSG_SIZE]; | ||
| 2344 | ✗ | my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err, | |
| 2345 | my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); | ||
| 2346 | ✗ | error = 1; | |
| 2347 | } | ||
| 2348 | |||
| 2349 | #ifdef WITH_WSREP | ||
| 2350 |
7/10✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 62 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 4 times.
|
70 | if (WSREP(thd) && (ht->flags & HTON_WSREP_REPLICATION)) { |
| 2351 |
1/24✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
4 | WSREP_DEBUG("ha_rollback_to_savepoint: run after_rollback hook"); |
| 2352 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | (void)wsrep_after_rollback(thd, !thd->in_sub_stmt); |
| 2353 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (thd->wsrep_trx().bf_aborted()) { |
| 2354 | 1 | thd->wsrep_cs().mark_force_bf_abort(); | |
| 2355 | } | ||
| 2356 | } | ||
| 2357 | #endif /* WITH_WSREP */ | ||
| 2358 | |||
| 2359 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
|
70 | assert(!thd->status_var_aggregated); |
| 2360 | 70 | thd->status_var.ha_rollback_count++; | |
| 2361 |
2/4✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
✗ Branch 3 not taken.
|
70 | ha_info->reset(); /* keep it conveniently zero-filled */ |
| 2362 | 4265 | } | |
| 2363 |
1/2✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
|
4265 | trn_ctx->set_ha_trx_info(trx_scope, sv->ha_list); |
| 2364 | |||
| 2365 | #ifdef HAVE_PSI_TRANSACTION_INTERFACE | ||
| 2366 |
2/2✓ Branch 0 taken 4264 times.
✓ Branch 1 taken 1 times.
|
4265 | if (thd->m_transaction_psi != nullptr) |
| 2367 |
1/2✓ Branch 0 taken 4264 times.
✗ Branch 1 not taken.
|
4264 | MYSQL_INC_TRANSACTION_ROLLBACK_TO_SAVEPOINT(thd->m_transaction_psi, 1); |
| 2368 | #endif | ||
| 2369 | |||
| 2370 | 4265 | thd->diff_rollback_trans++; | |
| 2371 | |||
| 2372 | 4265 | return error; | |
| 2373 | 4265 | } | |
| 2374 | |||
| 2375 | 4974222 | int ha_prepare_low(THD *thd, bool all) { | |
| 2376 |
1/2✓ Branch 0 taken 4974291 times.
✗ Branch 1 not taken.
|
4974222 | DBUG_TRACE; |
| 2377 | 4974291 | int error = 0; | |
| 2378 | 4974291 | Transaction_ctx::enum_trx_scope trx_scope = | |
| 2379 |
2/2✓ Branch 0 taken 536782 times.
✓ Branch 1 taken 4437509 times.
|
4974291 | all ? Transaction_ctx::SESSION : Transaction_ctx::STMT; |
| 2380 |
1/2✓ Branch 0 taken 4974279 times.
✗ Branch 1 not taken.
|
4974291 | auto ha_list = thd->get_transaction()->ha_trx_info(trx_scope); |
| 2381 | |||
| 2382 |
2/4✓ Branch 0 taken 4974288 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4974288 times.
✗ Branch 3 not taken.
|
4974279 | if (ha_list) { |
| 2383 |
7/12✓ Branch 0 taken 4974296 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4974290 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9948459 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9948361 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14922594 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9948441 times.
✓ Branch 11 taken 4974153 times.
|
14922580 | for (auto const &ha_info : ha_list) { |
| 2384 |
4/6✓ Branch 0 taken 9948499 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 9948489 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9948499 times.
|
9948469 | if (!ha_info.is_trx_read_write() && // Do not call two-phase commit if |
| 2385 | // transaction is read-only | ||
| 2386 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
|
10 | !thd_holds_xa_transaction(thd)) // but only if is not an XA |
| 2387 | // transaction | ||
| 2388 | ✗ | continue; | |
| 2389 | |||
| 2390 | 9948499 | auto ht = ha_info.ht(); | |
| 2391 | |||
| 2392 | #ifdef WITH_WSREP | ||
| 2393 |
1/2✓ Branch 0 taken 9948497 times.
✗ Branch 1 not taken.
|
9948481 | const bool run_wsrep_hooks = wsrep_run_commit_hook(thd, all); |
| 2394 | int err; | ||
| 2395 | |||
| 2396 |
6/6✓ Branch 0 taken 92950 times.
✓ Branch 1 taken 9855547 times.
✓ Branch 2 taken 46474 times.
✓ Branch 3 taken 46476 times.
✓ Branch 4 taken 202 times.
✓ Branch 5 taken 9948294 times.
|
9994970 | if (run_wsrep_hooks && (ht->flags & HTON_WSREP_REPLICATION) && |
| 2397 |
3/4✓ Branch 0 taken 46473 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 202 times.
✓ Branch 3 taken 46271 times.
|
46474 | (err = wsrep_before_prepare(thd, all))) { |
| 2398 | // before prepare can fail during certify due to local certification | ||
| 2399 | // failure but it should get communicated as generic deadlock error. | ||
| 2400 |
1/24✗ Branch 0 not taken.
✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
202 | WSREP_DEBUG( |
| 2401 | "wsrep_before_prepare hook (replication + certification)" | ||
| 2402 | " failed to execute"); | ||
| 2403 |
1/2✓ Branch 0 taken 202 times.
✗ Branch 1 not taken.
|
202 | mysql_mutex_lock(&thd->LOCK_wsrep_thd); |
| 2404 | 202 | bool must_replay = wsrep_must_replay(thd); | |
| 2405 |
1/2✓ Branch 0 taken 202 times.
✗ Branch 1 not taken.
|
202 | mysql_mutex_unlock(&thd->LOCK_wsrep_thd); |
| 2406 |
2/2✓ Branch 0 taken 126 times.
✓ Branch 1 taken 76 times.
|
202 | if (!must_replay) { |
| 2407 |
2/2✓ Branch 0 taken 124 times.
✓ Branch 1 taken 2 times.
|
126 | if (thd->wsrep_cs().current_error() == wsrep::e_size_exceeded_error) { |
| 2408 | // retain existing error code and message | ||
| 2409 | } else { | ||
| 2410 | /* set error only if transaction is not marked for replay. */ | ||
| 2411 | char errbuf[MYSQL_ERRMSG_SIZE]; | ||
| 2412 |
2/4✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 124 times.
✗ Branch 3 not taken.
|
124 | my_error(ER_LOCK_DEADLOCK, MYF(0), err, |
| 2413 | my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); | ||
| 2414 | } | ||
| 2415 | } | ||
| 2416 | |||
| 2417 | 202 | error = 1; | |
| 2418 | 202 | continue; | |
| 2419 | 202 | } | |
| 2420 | |||
| 2421 | /* core-prepare logic is no more affected by the pxc error. | ||
| 2422 | pxc replication and certification is now take care above as part of | ||
| 2423 | wsrep_before_prepare. */ | ||
| 2424 |
1/2✓ Branch 0 taken 9948218 times.
✗ Branch 1 not taken.
|
9948294 | err = ht->prepare(ht, thd, all); |
| 2425 |
2/2✓ Branch 0 taken 122 times.
✓ Branch 1 taken 9948096 times.
|
9948218 | if (err) { |
| 2426 |
3/4✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✓ Branch 3 taken 1 times.
|
122 | if (!thd_holds_xa_transaction( |
| 2427 | thd)) { // If XA PREPARE, let error be handled by caller | ||
| 2428 | char errbuf[MYSQL_ERRMSG_SIZE]; | ||
| 2429 |
2/4✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
|
121 | my_error(ER_ERROR_DURING_COMMIT, MYF(0), err, |
| 2430 | my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); | ||
| 2431 | } | ||
| 2432 | 122 | error = 1; | |
| 2433 | } | ||
| 2434 | |||
| 2435 |
8/8✓ Branch 0 taken 92744 times.
✓ Branch 1 taken 9855474 times.
✓ Branch 2 taken 92743 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 46271 times.
✓ Branch 5 taken 46472 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 9948212 times.
|
9994489 | if (run_wsrep_hooks && !error && (ht->flags & HTON_WSREP_REPLICATION) && |
| 2436 |
3/4✓ Branch 0 taken 46271 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 46265 times.
|
46271 | wsrep_after_prepare(thd, all)) { |
| 2437 |
1/24✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
6 | WSREP_DEBUG( |
| 2438 | "wsrep_after_prepare hook (replication + certification)" | ||
| 2439 | " failed to execute"); | ||
| 2440 | char errbuf[MYSQL_ERRMSG_SIZE]; | ||
| 2441 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | my_error(ER_LOCK_DEADLOCK, MYF(0), err, |
| 2442 | my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); | ||
| 2443 | 6 | error = 1; | |
| 2444 | } | ||
| 2445 | #else | ||
| 2446 | int err = ht->prepare(ht, thd, all); | ||
| 2447 | if (err) { | ||
| 2448 | if (!thd_holds_xa_transaction( | ||
| 2449 | thd)) { // If XA PREPARE, let error be handled by caller | ||
| 2450 | char errbuf[MYSQL_ERRMSG_SIZE]; | ||
| 2451 | my_error(ER_ERROR_DURING_COMMIT, MYF(0), err, | ||
| 2452 | my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); | ||
| 2453 | } | ||
| 2454 | error = 1; | ||
| 2455 | } | ||
| 2456 | #endif /* WITH_WSREP */ | ||
| 2457 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9948218 times.
|
9948218 | assert(!thd->status_var_aggregated); |
| 2458 | 9948218 | thd->status_var.ha_prepare_count++; | |
| 2459 | |||
| 2460 |
2/2✓ Branch 0 taken 128 times.
✓ Branch 1 taken 9948090 times.
|
9948218 | if (error) break; |
| 2461 | 4974281 | } | |
| 2462 |
4/6✓ Branch 0 taken 4974292 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 4974283 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
4974295 | DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE();); |
| 2463 | } | ||
| 2464 | |||
| 2465 | 4974287 | return error; | |
| 2466 | 4974283 | } | |
| 2467 | |||
| 2468 | /** | ||
| 2469 | @note | ||
| 2470 | according to the sql standard (ISO/IEC 9075-2:2003) | ||
| 2471 | section "4.33.4 SQL-statements and transaction states", | ||
| 2472 | SAVEPOINT is *not* transaction-initiating SQL-statement | ||
| 2473 | */ | ||
| 2474 | 8279 | int ha_savepoint(THD *thd, SAVEPOINT *sv) { | |
| 2475 | #if 0 | ||
| 2476 | /* commenting it out for now. | ||
| 2477 | it was not present in 5.7. there is no reason explained why | ||
| 2478 | it was added in 8.x. out-of-order registering binlog handler | ||
| 2479 | for savepoint causes issues rolling back acting local trx | ||
| 2480 | executing rollback to savepoint when it is killed by high priority | ||
| 2481 | trx. | ||
| 2482 | */ | ||
| 2483 | #ifdef WITH_WSREP | ||
| 2484 | /* | ||
| 2485 | Register binlog hton for savepoint processing if wsrep binlog | ||
| 2486 | emulation is on. | ||
| 2487 | */ | ||
| 2488 | if (WSREP_EMULATE_BINLOG(thd) && wsrep_thd_is_local(thd)) { | ||
| 2489 | wsrep_register_binlog_handler(thd, thd->in_multi_stmt_transaction_mode()); | ||
| 2490 | } | ||
| 2491 | #endif /* WITH_WSREP */ | ||
| 2492 | #endif | ||
| 2493 | |||
| 2494 | 8279 | int error = 0; | |
| 2495 | 8279 | Transaction_ctx::enum_trx_scope trx_scope = | |
| 2496 |
2/2✓ Branch 0 taken 8190 times.
✓ Branch 1 taken 89 times.
|
8279 | !thd->in_sub_stmt ? Transaction_ctx::SESSION : Transaction_ctx::STMT; |
| 2497 | |||
| 2498 |
1/2✓ Branch 0 taken 8279 times.
✗ Branch 1 not taken.
|
8279 | DBUG_TRACE; |
| 2499 | |||
| 2500 |
1/2✓ Branch 0 taken 8279 times.
✗ Branch 1 not taken.
|
8279 | auto ha_list = thd->get_transaction()->ha_trx_info(trx_scope); |
| 2501 |
6/10✓ Branch 0 taken 8279 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8279 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16097 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 24376 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 16097 times.
✓ Branch 9 taken 8279 times.
|
24377 | for (auto const &ha_info : ha_list) { |
| 2502 | int err; | ||
| 2503 | 16097 | auto ht = ha_info.ht(); | |
| 2504 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16096 times.
|
16097 | assert(ht); |
| 2505 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16096 times.
|
16096 | if (!ht->savepoint_set) { |
| 2506 | ✗ | my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "SAVEPOINT"); | |
| 2507 | ✗ | error = 1; | |
| 2508 | ✗ | break; | |
| 2509 | } | ||
| 2510 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16098 times.
|
16098 | if ((err = ht->savepoint_set( |
| 2511 | ht, thd, | ||
| 2512 |
1/2✓ Branch 0 taken 16098 times.
✗ Branch 1 not taken.
|
16096 | (uchar *)(sv + 1) + ht->savepoint_offset))) { // cannot happen |
| 2513 | char errbuf[MYSQL_ERRMSG_SIZE]; | ||
| 2514 | ✗ | my_error(ER_GET_ERRNO, MYF(0), err, | |
| 2515 | my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); | ||
| 2516 | ✗ | error = 1; | |
| 2517 | } | ||
| 2518 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16098 times.
|
16098 | assert(!thd->status_var_aggregated); |
| 2519 |
1/2✓ Branch 0 taken 16098 times.
✗ Branch 1 not taken.
|
16098 | thd->status_var.ha_savepoint_count++; |
| 2520 | 8279 | } | |
| 2521 | /* | ||
| 2522 | Remember the list of registered storage engines. All new | ||
| 2523 | engines are prepended to the beginning of the list. | ||
| 2524 | */ | ||
| 2525 |
1/2✓ Branch 0 taken 8279 times.
✗ Branch 1 not taken.
|
8279 | sv->ha_list = ha_list.head(); |
| 2526 | |||
| 2527 | #ifdef HAVE_PSI_TRANSACTION_INTERFACE | ||
| 2528 |
3/4✓ Branch 0 taken 8279 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8275 times.
✓ Branch 3 taken 4 times.
|
8279 | if (!error && thd->m_transaction_psi != nullptr) |
| 2529 |
1/2✓ Branch 0 taken 8275 times.
✗ Branch 1 not taken.
|
8275 | MYSQL_INC_TRANSACTION_SAVEPOINTS(thd->m_transaction_psi, 1); |
| 2530 | #endif | ||
| 2531 | |||
| 2532 | 8279 | return error; | |
| 2533 | 8279 | } | |
| 2534 | |||
| 2535 | 137 | int ha_release_savepoint(THD *thd, SAVEPOINT *sv) { | |
| 2536 | 137 | int error = 0; | |
| 2537 |
1/2✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
|
137 | DBUG_TRACE; |
| 2538 | |||
| 2539 |
1/2✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
|
137 | Ha_trx_info_list ha_list{sv->ha_list}; |
| 2540 |
7/12✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 196 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 196 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 333 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 196 times.
✓ Branch 11 taken 137 times.
|
333 | for (auto const &ha_info : ha_list) { |
| 2541 | int err; | ||
| 2542 | 196 | auto ht = ha_info.ht(); | |
| 2543 | /* Savepoint life time is enclosed into transaction life time. */ | ||
| 2544 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 196 times.
|
196 | assert(ht); |
| 2545 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 126 times.
|
196 | if (!ht->savepoint_release) continue; |
| 2546 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
|
126 | if ((err = ht->savepoint_release( |
| 2547 | ht, thd, | ||
| 2548 |
1/2✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
|
126 | (uchar *)(sv + 1) + ht->savepoint_offset))) { // cannot happen |
| 2549 | char errbuf[MYSQL_ERRMSG_SIZE]; | ||
| 2550 | ✗ | my_error(ER_GET_ERRNO, MYF(0), err, | |
| 2551 | my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); | ||
| 2552 | ✗ | error = 1; | |
| 2553 | } | ||
| 2554 | 137 | } | |
| 2555 |
4/6✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 136 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
137 | DBUG_EXECUTE_IF("fail_ha_release_savepoint", { |
| 2556 | my_error(ER_UNKNOWN_ERROR, MYF(0)); | ||
| 2557 | error = 1; | ||
| 2558 | }); | ||
| 2559 | |||
| 2560 | #ifdef HAVE_PSI_TRANSACTION_INTERFACE | ||
| 2561 |
2/2✓ Branch 0 taken 136 times.
✓ Branch 1 taken 1 times.
|
137 | if (thd->m_transaction_psi != nullptr) |
| 2562 |
1/2✓ Branch 0 taken 136 times.
✗ Branch 1 not taken.
|
136 | MYSQL_INC_TRANSACTION_RELEASE_SAVEPOINT(thd->m_transaction_psi, 1); |
| 2563 | #endif | ||
| 2564 | 137 | return error; | |
| 2565 | 137 | } | |
| 2566 | |||
| 2567 | 231 | static bool clone_snapshot_handlerton(THD *thd, plugin_ref plugin, void *arg) { | |
| 2568 | 231 | handlerton *const hton = plugin_data<handlerton *>(plugin); | |
| 2569 | |||
| 2570 |
3/4✓ Branch 0 taken 231 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 189 times.
|
231 | if (hton->state == SHOW_OPTION_YES && hton->clone_consistent_snapshot) |
| 2571 | 42 | hton->clone_consistent_snapshot(hton, thd, static_cast<THD *>(arg)); | |
| 2572 | |||
| 2573 | 231 | return false; | |
| 2574 | } | ||
| 2575 | |||
| 2576 | 26 | static int ha_clone_consistent_snapshot(THD *thd) { | |
| 2577 | 26 | THD_ptr from_thd_ptr; | |
| 2578 | ulong id; | ||
| 2579 | 26 | Item *val = thd->lex->donor_transaction_id; | |
| 2580 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | assert(val); |
| 2581 | |||
| 2582 |
3/4✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 25 times.
|
26 | if (thd->lex->table_or_sp_used()) { |
| 2583 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_NOT_SUPPORTED_YET, MYF(0), |
| 2584 | "Usage of subqueries or stored " | ||
| 2585 | "function calls as part of this statement"); | ||
| 2586 | 1 | goto error; | |
| 2587 | } | ||
| 2588 | |||
| 2589 |
9/12✓ Branch 0 taken 2 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 24 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 24 times.
|
25 | if ((!val->fixed && val->fix_fields(thd, &val)) || val->check_cols(1)) { |
| 2590 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_SET_CONSTANTS_ONLY, MYF(0)); |
| 2591 | 1 | goto error; | |
| 2592 | } | ||
| 2593 | |||
| 2594 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | id = val->val_int(); |
| 2595 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 23 times.
|
24 | if (thd->thread_id() == id) { |
| 2596 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_NO_SUCH_THREAD, MYF(0), id); |
| 2597 | 1 | goto error; | |
| 2598 | } | ||
| 2599 | |||
| 2600 | { | ||
| 2601 | 23 | Find_thd_with_id find_thd_with_id(id, true); | |
| 2602 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | from_thd_ptr = Global_THD_manager::get_instance()->find_thd(&find_thd_with_id); |
| 2603 | |||
| 2604 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 21 times.
|
23 | if (!from_thd_ptr) { |
| 2605 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_NO_SUCH_THREAD, MYF(0), id); |
| 2606 | 2 | goto error; | |
| 2607 | } | ||
| 2608 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
|
23 | } |
| 2609 | |||
| 2610 | /* | ||
| 2611 | Blocking commits and binlog updates ensures that we get the same snapshot | ||
| 2612 | for all engines (including the binary log). This allows us among other | ||
| 2613 | things to do backups with START TRANSACTION WITH CONSISTENT SNAPSHOT and | ||
| 2614 | have a consistent binlog position. | ||
| 2615 | */ | ||
| 2616 |
1/2✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
|
21 | tc_log->xlock(); |
| 2617 | |||
| 2618 |
1/2✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
|
21 | plugin_foreach(thd, clone_snapshot_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, |
| 2619 | from_thd_ptr.get()); | ||
| 2620 | |||
| 2621 |
1/2✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
|
21 | tc_log->xunlock(); |
| 2622 | |||
| 2623 | 21 | return 0; | |
| 2624 | |||
| 2625 | 5 | error: | |
| 2626 | |||
| 2627 | 5 | return 1; | |
| 2628 | 26 | } | |
| 2629 | |||
| 2630 | 704 | static bool start_snapshot_handlerton(THD *thd, plugin_ref plugin, void *arg) { | |
| 2631 | 704 | handlerton *const hton = plugin_data<handlerton *>(plugin); | |
| 2632 |
4/4✓ Branch 0 taken 695 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 119 times.
✓ Branch 3 taken 576 times.
|
704 | if (hton->state == SHOW_OPTION_YES && hton->start_consistent_snapshot) { |
| 2633 | 119 | hton->start_consistent_snapshot(hton, thd); | |
| 2634 | 119 | *((bool *)arg) = false; | |
| 2635 | } | ||
| 2636 | 704 | return false; | |
| 2637 | } | ||
| 2638 | |||
| 2639 | 90 | int ha_start_consistent_snapshot(THD *thd) { | |
| 2640 |
3/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
|
90 | if (thd->lex->donor_transaction_id) return ha_clone_consistent_snapshot(thd); |
| 2641 | 64 | bool warn = true; | |
| 2642 | |||
| 2643 | /* | ||
| 2644 | Blocking commits and binlog updates ensures that we get the same snapshot | ||
| 2645 | for all engines (including the binary log). This allows us among other | ||
| 2646 | things to do backups with START TRANSACTION WITH CONSISTENT SNAPSHOT and | ||
| 2647 | have a consistent binlog position. | ||
| 2648 | */ | ||
| 2649 |
1/2✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
|
64 | tc_log->xlock(); |
| 2650 | |||
| 2651 |
1/2✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
|
64 | plugin_foreach(thd, start_snapshot_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, |
| 2652 | &warn); | ||
| 2653 | |||
| 2654 |
1/2✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
|
64 | tc_log->xunlock(); |
| 2655 | |||
| 2656 | /* | ||
| 2657 | Same idea as when one wants to CREATE TABLE in one engine which does not | ||
| 2658 | exist: | ||
| 2659 | */ | ||
| 2660 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 | if (warn) |
| 2661 | ✗ | push_warning(thd, Sql_condition::SL_WARNING, ER_UNKNOWN_ERROR, | |
| 2662 | "This MySQL server does not support any " | ||
| 2663 | "consistent-read capable storage engine"); | ||
| 2664 | 64 | return 0; | |
| 2665 | } | ||
| 2666 | |||
| 2667 | 2739 | static bool store_binlog_info_handlerton(THD *thd, plugin_ref plugin, | |
| 2668 | void *arg) { | ||
| 2669 | 2739 | handlerton *const hton = plugin_data<handlerton *>(plugin); | |
| 2670 | |||
| 2671 |
3/4✓ Branch 0 taken 2739 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 249 times.
✓ Branch 3 taken 2490 times.
|
2739 | if (hton->state == SHOW_OPTION_YES && hton->store_binlog_info) { |
| 2672 | 249 | hton->store_binlog_info(hton, thd); | |
| 2673 | 249 | *(static_cast<bool *>(arg)) = false; | |
| 2674 | } | ||
| 2675 | |||
| 2676 | 2739 | return false; | |
| 2677 | } | ||
| 2678 | |||
| 2679 | 254 | int ha_store_binlog_info(THD *thd) { | |
| 2680 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 249 times.
|
254 | if (!mysql_bin_log.is_open()) return 0; |
| 2681 | |||
| 2682 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
|
249 | assert(tc_log == &mysql_bin_log); |
| 2683 | |||
| 2684 | 249 | LOG_INFO li; | |
| 2685 | 249 | bool warn = true; | |
| 2686 | |||
| 2687 | /* Block commits to get consistent binlog coordinates */ | ||
| 2688 |
1/2✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
|
249 | tc_log->xlock(); |
| 2689 | |||
| 2690 |
1/2✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
|
249 | mysql_bin_log.raw_get_current_log(&li); |
| 2691 |
1/2✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
|
249 | thd->set_trans_pos(li.log_file_name, li.pos); |
| 2692 | |||
| 2693 |
1/2✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
|
249 | plugin_foreach(thd, store_binlog_info_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, |
| 2694 | &warn); | ||
| 2695 | |||
| 2696 |
1/2✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
|
249 | tc_log->xunlock(); |
| 2697 | |||
| 2698 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
|
249 | if (warn) |
| 2699 | ✗ | push_warning(thd, Sql_condition::SL_WARNING, ER_UNKNOWN_ERROR, | |
| 2700 | "No support for storing binlog coordinates in any storage"); | ||
| 2701 | 249 | return 0; | |
| 2702 | } | ||
| 2703 | |||
| 2704 | 28239695 | static bool flush_handlerton(THD *, plugin_ref plugin, void *arg) { | |
| 2705 | 28239695 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 2706 |
5/6✓ Branch 0 taken 28236623 times.
✓ Branch 1 taken 3068 times.
✓ Branch 2 taken 2567153 times.
✓ Branch 3 taken 25669470 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 28239658 times.
|
30806811 | if (hton->state == SHOW_OPTION_YES && hton->flush_logs && |
| 2707 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2567120 times.
|
2567153 | hton->flush_logs(hton, *(static_cast<bool *>(arg)))) |
| 2708 | ✗ | return true; | |
| 2709 | 28239658 | return false; | |
| 2710 | } | ||
| 2711 | |||
| 2712 | 2567153 | bool ha_flush_logs(bool binlog_group_flush) { | |
| 2713 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2567120 times.
|
2567153 | if (plugin_foreach(nullptr, flush_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, |
| 2714 | static_cast<void *>(&binlog_group_flush))) { | ||
| 2715 | ✗ | return true; | |
| 2716 | } | ||
| 2717 | 2567120 | return false; | |
| 2718 | } | ||
| 2719 | |||
| 2720 | /** | ||
| 2721 | @brief make canonical filename | ||
| 2722 | |||
| 2723 | @param[in] file table handler | ||
| 2724 | @param[in] path original path | ||
| 2725 | @param[out] tmp_path buffer for canonized path | ||
| 2726 | |||
| 2727 | @details Lower case db name and table name path parts for | ||
| 2728 | non file based tables when lower_case_table_names | ||
| 2729 | is 2 (store as is, compare in lower case). | ||
| 2730 | Filesystem path prefix (mysql_data_home or tmpdir) | ||
| 2731 | is left intact. | ||
| 2732 | |||
| 2733 | @note tmp_path may be left intact if no conversion was | ||
| 2734 | performed. | ||
| 2735 | |||
| 2736 | @retval canonized path | ||
| 2737 | |||
| 2738 | @todo This may be done more efficiently when table path | ||
| 2739 | gets built. Convert this function to something like | ||
| 2740 | ASSERT_CANONICAL_FILENAME. | ||
| 2741 | */ | ||
| 2742 | 499379 | const char *get_canonical_filename(handler *file, const char *path, | |
| 2743 | char *tmp_path) { | ||
| 2744 | uint i; | ||
| 2745 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 499379 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 499379 times.
✗ Branch 5 not taken.
|
499379 | if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED)) |
| 2746 | 499379 | return path; | |
| 2747 | |||
| 2748 | ✗ | for (i = 0; i <= mysql_tmpdir_list.max; i++) { | |
| 2749 | ✗ | if (is_prefix(path, mysql_tmpdir_list.list[i])) return path; | |
| 2750 | } | ||
| 2751 | |||
| 2752 | /* Ensure that table handler get path in lower case */ | ||
| 2753 | ✗ | if (tmp_path != path) my_stpcpy(tmp_path, path); | |
| 2754 | |||
| 2755 | /* | ||
| 2756 | we only should turn into lowercase database/table part | ||
| 2757 | so start the process after homedirectory | ||
| 2758 | */ | ||
| 2759 | ✗ | my_casedn_str(files_charset_info, tmp_path + mysql_data_home_len); | |
| 2760 | ✗ | return tmp_path; | |
| 2761 | } | ||
| 2762 | |||
| 2763 | class Ha_delete_table_error_handler : public Internal_error_handler { | ||
| 2764 | public: | ||
| 2765 | 19 | bool handle_condition(THD *, uint, const char *, | |
| 2766 | Sql_condition::enum_severity_level *level, | ||
| 2767 | const char *) override { | ||
| 2768 | /* Downgrade errors to warnings. */ | ||
| 2769 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | if (*level == Sql_condition::SL_ERROR) *level = Sql_condition::SL_WARNING; |
| 2770 | 19 | return false; | |
| 2771 | } | ||
| 2772 | }; | ||
| 2773 | |||
| 2774 | /** | ||
| 2775 | Delete table from the storage engine. | ||
| 2776 | |||
| 2777 | @param thd Thread context. | ||
| 2778 | @param table_type Handlerton for table's SE. | ||
| 2779 | @param path Path to table (without extension). | ||
| 2780 | @param db Table database. | ||
| 2781 | @param alias Table name. | ||
| 2782 | @param table_def dd::Table object describing the table. | ||
| 2783 | @param generate_warning Indicates whether errors during deletion | ||
| 2784 | should be reported as warnings. | ||
| 2785 | |||
| 2786 | @return 0 - in case of success, non-0 in case of failure, ENOENT | ||
| 2787 | if the file doesn't exists. | ||
| 2788 | */ | ||
| 2789 | 169750 | int ha_delete_table(THD *thd, handlerton *table_type, const char *path, | |
| 2790 | const char *db, const char *alias, | ||
| 2791 | const dd::Table *table_def, bool generate_warning) { | ||
| 2792 | handler *file; | ||
| 2793 | char tmp_path[FN_REFLEN]; | ||
| 2794 | int error; | ||
| 2795 |
1/2✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
|
169750 | TABLE dummy_table; |
| 2796 |
1/2✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
|
169750 | TABLE_SHARE dummy_share; |
| 2797 |
1/2✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
|
169750 | DBUG_TRACE; |
| 2798 | |||
| 2799 | 169750 | dummy_table.s = &dummy_share; | |
| 2800 | |||
| 2801 | /* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */ | ||
| 2802 |
2/4✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 169750 times.
|
339500 | if (table_type == nullptr || |
| 2803 | !(file = | ||
| 2804 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 169750 times.
|
169750 | get_new_handler((TABLE_SHARE *)nullptr, |
| 2805 |
2/4✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 169750 times.
✗ Branch 3 not taken.
|
169750 | table_def->partition_type() != dd::Table::PT_NONE, |
| 2806 | thd->mem_root, table_type))) { | ||
| 2807 | ✗ | return ENOENT; | |
| 2808 | } | ||
| 2809 | |||
| 2810 |
1/2✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
|
169750 | path = get_canonical_filename(file, path, tmp_path); |
| 2811 | |||
| 2812 |
7/8✓ Branch 0 taken 169741 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 169717 times.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 19 times.
✓ Branch 7 taken 169722 times.
|
169750 | if ((error = file->ha_delete_table(path, table_def)) && generate_warning) { |
| 2813 | /* | ||
| 2814 | Because file->print_error() use my_error() to generate the error message | ||
| 2815 | we use an internal error handler to intercept it and store the text | ||
| 2816 | in a temporary buffer. Later the message will be presented to user | ||
| 2817 | as a warning. | ||
| 2818 | */ | ||
| 2819 | 19 | Ha_delete_table_error_handler ha_delete_table_error_handler; | |
| 2820 | |||
| 2821 | /* Fill up strucutures that print_error may need */ | ||
| 2822 | 19 | dummy_share.path.str = const_cast<char *>(path); | |
| 2823 | 19 | dummy_share.path.length = strlen(path); | |
| 2824 | 19 | dummy_share.db.str = db; | |
| 2825 | 19 | dummy_share.db.length = strlen(db); | |
| 2826 | 19 | dummy_share.table_name.str = alias; | |
| 2827 | 19 | dummy_share.table_name.length = strlen(alias); | |
| 2828 | 19 | dummy_table.alias = alias; | |
| 2829 | |||
| 2830 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | file->change_table_ptr(&dummy_table, &dummy_share); |
| 2831 | |||
| 2832 | /* | ||
| 2833 | XXX: should we convert *all* errors to warnings here? | ||
| 2834 | What if the error is fatal? | ||
| 2835 | */ | ||
| 2836 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | thd->push_internal_handler(&ha_delete_table_error_handler); |
| 2837 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | file->print_error(error, 0); |
| 2838 | |||
| 2839 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | thd->pop_internal_handler(); |
| 2840 | 19 | } | |
| 2841 | |||
| 2842 |
2/2✓ Branch 0 taken 169717 times.
✓ Branch 1 taken 24 times.
|
169741 | if (error == 0) { |
| 2843 |
1/2✓ Branch 0 taken 169716 times.
✗ Branch 1 not taken.
|
169717 | bool failure = compression_dict::cols_table_delete(thd, *table_def); |
| 2844 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 169715 times.
|
169716 | if (failure) { |
| 2845 |
3/30✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
|
1 | DBUG_LOG("zip_dict", |
| 2846 | "Removing entry from compression dictionary cols" | ||
| 2847 | " failed for table: " | ||
| 2848 | << table_def->name() | ||
| 2849 | << " and table_id: " << table_def->id()); | ||
| 2850 | 1 | error = ER_UNKNOWN_ERROR; | |
| 2851 | } | ||
| 2852 | } | ||
| 2853 | |||
| 2854 | 169740 | destroy(file); | |
| 2855 | |||
| 2856 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 2857 |
2/2✓ Branch 0 taken 169716 times.
✓ Branch 1 taken 25 times.
|
169741 | if (likely(error == 0)) { |
| 2858 | /* Table share not available, so check path for temp_table prefix. */ | ||
| 2859 | 169716 | bool temp_table = (strstr(path, tmp_file_prefix) != nullptr); | |
| 2860 | PSI_TABLE_CALL(drop_table_share) | ||
| 2861 |
1/2✓ Branch 0 taken 169716 times.
✗ Branch 1 not taken.
|
169716 | (temp_table, db, strlen(db), alias, strlen(alias)); |
| 2862 | } | ||
| 2863 | #endif | ||
| 2864 | |||
| 2865 | 169741 | return error; | |
| 2866 | 169741 | } | |
| 2867 | |||
| 2868 | // Prepare HA_CREATE_INFO to be used by ALTER as well as upgrade code. | ||
| 2869 | 109146 | void HA_CREATE_INFO::init_create_options_from_share(const TABLE_SHARE *share, | |
| 2870 | uint64_t used_fields) { | ||
| 2871 |
2/2✓ Branch 0 taken 109134 times.
✓ Branch 1 taken 12 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_MIN_ROWS)) min_rows = share->min_rows; |
| 2872 | |||
| 2873 |
2/2✓ Branch 0 taken 109126 times.
✓ Branch 1 taken 20 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_MAX_ROWS)) max_rows = share->max_rows; |
| 2874 | |||
| 2875 |
2/2✓ Branch 0 taken 109134 times.
✓ Branch 1 taken 12 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH)) |
| 2876 | 109134 | avg_row_length = share->avg_row_length; | |
| 2877 | |||
| 2878 |
2/2✓ Branch 0 taken 106449 times.
✓ Branch 1 taken 2697 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET)) |
| 2879 | 106449 | default_table_charset = share->table_charset; | |
| 2880 | |||
| 2881 |
2/2✓ Branch 0 taken 109062 times.
✓ Branch 1 taken 84 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE)) |
| 2882 | 109062 | key_block_size = share->key_block_size; | |
| 2883 | |||
| 2884 |
2/2✓ Branch 0 taken 109143 times.
✓ Branch 1 taken 3 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_STATS_SAMPLE_PAGES)) |
| 2885 | 109143 | stats_sample_pages = share->stats_sample_pages; | |
| 2886 | |||
| 2887 |
2/2✓ Branch 0 taken 109139 times.
✓ Branch 1 taken 7 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_STATS_AUTO_RECALC)) |
| 2888 | 109139 | stats_auto_recalc = share->stats_auto_recalc; | |
| 2889 | |||
| 2890 |
2/2✓ Branch 0 taken 103342 times.
✓ Branch 1 taken 5804 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_TABLESPACE)) |
| 2891 | 103342 | tablespace = share->tablespace; | |
| 2892 | |||
| 2893 |
2/2✓ Branch 0 taken 109142 times.
✓ Branch 1 taken 4 times.
|
109146 | if (storage_media == HA_SM_DEFAULT) |
| 2894 | 109142 | storage_media = share->default_storage_media; | |
| 2895 | |||
| 2896 | /* Creation of federated table with LIKE clause needs connection string */ | ||
| 2897 |
1/2✓ Branch 0 taken 109146 times.
✗ Branch 1 not taken.
|
109146 | if (!(used_fields & HA_CREATE_USED_CONNECTION)) |
| 2898 | 109146 | connect_string = share->connect_string; | |
| 2899 | |||
| 2900 |
2/2✓ Branch 0 taken 108173 times.
✓ Branch 1 taken 973 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_COMMENT)) { |
| 2901 | // Assert to check that used_fields flag and comment are in sync. | ||
| 2902 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 108173 times.
|
108173 | assert(!comment.str); |
| 2903 | 108173 | comment = share->comment; | |
| 2904 | } | ||
| 2905 | |||
| 2906 |
2/2✓ Branch 0 taken 109072 times.
✓ Branch 1 taken 74 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_COMPRESS)) { |
| 2907 | // Assert to check that used_fields flag and compress are in sync | ||
| 2908 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109072 times.
|
109072 | assert(!compress.str); |
| 2909 | 109072 | compress = share->compress; | |
| 2910 | } | ||
| 2911 | |||
| 2912 |
2/2✓ Branch 0 taken 104069 times.
✓ Branch 1 taken 5077 times.
|
109146 | if (!(used_fields & (HA_CREATE_USED_ENCRYPT))) { |
| 2913 | // Assert to check that used_fields flag and encrypt_type are in sync | ||
| 2914 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 104069 times.
|
104069 | assert(!encrypt_type.str); |
| 2915 | 104069 | encrypt_type = share->encrypt_type; | |
| 2916 | 104069 | explicit_encryption = share->explicit_encryption; | |
| 2917 | } else { | ||
| 2918 | 5077 | explicit_encryption = true; | |
| 2919 | } | ||
| 2920 | |||
| 2921 |
2/2✓ Branch 0 taken 109078 times.
✓ Branch 1 taken 68 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_SECONDARY_ENGINE)) { |
| 2922 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109078 times.
|
109078 | assert(secondary_engine.str == nullptr); |
| 2923 | 109078 | secondary_engine = share->secondary_engine; | |
| 2924 | } | ||
| 2925 | |||
| 2926 |
2/2✓ Branch 0 taken 104111 times.
✓ Branch 1 taken 5035 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_AUTOEXTEND_SIZE)) { |
| 2927 | /* m_implicit_tablespace_autoextend_size = 0 is a valid value. Hence, | ||
| 2928 | we need a mechanism to indicate the value change. */ | ||
| 2929 | 104111 | m_implicit_tablespace_autoextend_size = share->autoextend_size; | |
| 2930 | 104111 | m_implicit_tablespace_autoextend_size_change = false; | |
| 2931 | } | ||
| 2932 | |||
| 2933 |
2/2✓ Branch 0 taken 107847 times.
✓ Branch 1 taken 1299 times.
|
109146 | if (!(used_fields & HA_CREATE_USED_ENCRYPTION_KEY_ID)) { |
| 2934 | 107847 | encryption_key_id = share->encryption_key_id; | |
| 2935 | 107847 | was_encryption_key_id_set = share->was_encryption_key_id_set; | |
| 2936 | } | ||
| 2937 | |||
| 2938 |
2/2✓ Branch 0 taken 109140 times.
✓ Branch 1 taken 6 times.
|
109146 | if (engine_attribute.str == nullptr) |
| 2939 | 109140 | engine_attribute = share->engine_attribute; | |
| 2940 | |||
| 2941 |
2/2✓ Branch 0 taken 109136 times.
✓ Branch 1 taken 10 times.
|
109146 | if (secondary_engine_attribute.str == nullptr) |
| 2942 | 109136 | secondary_engine_attribute = share->secondary_engine_attribute; | |
| 2943 | 109146 | } | |
| 2944 | |||
| 2945 | /**************************************************************************** | ||
| 2946 | ** General handler functions | ||
| 2947 | ****************************************************************************/ | ||
| 2948 | 438583 | handler *handler::clone(const char *name, MEM_ROOT *mem_root) { | |
| 2949 |
1/2✓ Branch 0 taken 438583 times.
✗ Branch 1 not taken.
|
438583 | DBUG_TRACE; |
| 2950 | |||
| 2951 | handler *new_handler = | ||
| 2952 |
2/4✓ Branch 0 taken 438583 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 438583 times.
✗ Branch 3 not taken.
|
438583 | table ? get_new_handler(table->s, (table->s->m_part_info != nullptr), |
| 2953 | mem_root, ht) | ||
| 2954 | 438583 | : nullptr; | |
| 2955 | |||
| 2956 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 438583 times.
|
438583 | if (!new_handler) return nullptr; |
| 2957 |
2/4✓ Branch 0 taken 438583 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 438583 times.
|
438583 | if (new_handler->set_ha_share_ref(ha_share)) goto err; |
| 2958 | |||
| 2959 | /* | ||
| 2960 | Allocate handler->ref here because otherwise ha_open will allocate it | ||
| 2961 | on this->table->mem_root and we will not be able to reclaim that memory | ||
| 2962 | when the clone handler object is destroyed. | ||
| 2963 | */ | ||
| 2964 | 438583 | if (!(new_handler->ref = | |
| 2965 |
2/4✓ Branch 0 taken 438583 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 438583 times.
|
438583 | (uchar *)mem_root->Alloc(ALIGN_SIZE(ref_length) * 2))) |
| 2966 | ✗ | goto err; | |
| 2967 | |||
| 2968 | 438583 | new_handler->cloned = true; | |
| 2969 | |||
| 2970 | /* | ||
| 2971 | TODO: Implement a more efficient way to have more than one index open for | ||
| 2972 | the same table instance. The ha_open call is not cacheable for clone. | ||
| 2973 | */ | ||
| 2974 |
3/4✓ Branch 0 taken 438583 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 438581 times.
|
438583 | if (new_handler->ha_open(table, name, table->db_stat, |
| 2975 | HA_OPEN_IGNORE_IF_LOCKED, | ||
| 2976 | 438583 | table->get_tmp_dd_table_ptr())) | |
| 2977 | 2 | goto err; | |
| 2978 | |||
| 2979 | 438581 | return new_handler; | |
| 2980 | |||
| 2981 | 2 | err: | |
| 2982 | 2 | destroy(new_handler); | |
| 2983 | 2 | return nullptr; | |
| 2984 | 438583 | } | |
| 2985 | |||
| 2986 | 1191240168 | void handler::ha_statistic_increment( | |
| 2987 | ulonglong System_status_var::*offset) const { | ||
| 2988 |
2/4✓ Branch 0 taken 1191241045 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1191241657 times.
✗ Branch 3 not taken.
|
1191240168 | if (table && table->in_use) (table->in_use->status_var.*offset)++; |
| 2989 | 1191240168 | } | |
| 2990 | |||
| 2991 | 2000269187 | THD *handler::ha_thd() const { | |
| 2992 |
2/2✓ Branch 0 taken 3684117 times.
✓ Branch 1 taken 1996586540 times.
|
2000269187 | if (unlikely(cloned)) return current_thd; |
| 2993 |
4/6✓ Branch 0 taken 1985164853 times.
✓ Branch 1 taken 11421687 times.
✓ Branch 2 taken 1985166941 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1985166897 times.
|
1996586540 | assert(table == nullptr || table->in_use == nullptr || |
| 2994 | table->in_use == current_thd); | ||
| 2995 |
3/4✓ Branch 0 taken 1985167962 times.
✓ Branch 1 taken 11418534 times.
✓ Branch 2 taken 1985168550 times.
✗ Branch 3 not taken.
|
1996586496 | return table != nullptr && table->in_use != nullptr ? table->in_use |
| 2996 | 1996586496 | : current_thd; | |
| 2997 | } | ||
| 2998 | |||
| 2999 | 106649895 | void handler::unbind_psi() { | |
| 3000 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 3001 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 106649895 times.
|
106649895 | assert(m_lock_type == F_UNLCK); |
| 3002 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 106649895 times.
|
106649895 | assert(inited == NONE); |
| 3003 | /* | ||
| 3004 | Notify the instrumentation that this table is not owned | ||
| 3005 | by this thread any more. | ||
| 3006 | */ | ||
| 3007 | 106649895 | PSI_TABLE_CALL(unbind_table)(m_psi); | |
| 3008 | #endif | ||
| 3009 | 106649886 | } | |
| 3010 | |||
| 3011 | 102491196 | void handler::rebind_psi() { | |
| 3012 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 3013 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102491196 times.
|
102491196 | assert(m_lock_type == F_UNLCK); |
| 3014 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102491196 times.
|
102491196 | assert(inited == NONE); |
| 3015 | /* | ||
| 3016 | Notify the instrumentation that this table is now owned | ||
| 3017 | by this thread. | ||
| 3018 | */ | ||
| 3019 | 102491196 | PSI_table_share *share_psi = ha_table_share_psi(table_share); | |
| 3020 | 102491814 | m_psi = PSI_TABLE_CALL(rebind_table)(share_psi, this, m_psi); | |
| 3021 | #endif | ||
| 3022 | 102491940 | } | |
| 3023 | |||
| 3024 | 15499064 | void handler::start_psi_batch_mode() { | |
| 3025 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 3026 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15499064 times.
|
15499064 | assert(m_psi_batch_mode == PSI_BATCH_MODE_NONE); |
| 3027 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15499064 times.
|
15499064 | assert(m_psi_locker == nullptr); |
| 3028 | 15499064 | m_psi_batch_mode = PSI_BATCH_MODE_STARTING; | |
| 3029 | 15499064 | m_psi_numrows = 0; | |
| 3030 | #endif | ||
| 3031 | 15499064 | } | |
| 3032 | |||
| 3033 | 15499023 | void handler::end_psi_batch_mode() { | |
| 3034 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 3035 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15499023 times.
|
15499023 | assert(m_psi_batch_mode != PSI_BATCH_MODE_NONE); |
| 3036 |
2/2✓ Branch 0 taken 1240523 times.
✓ Branch 1 taken 14258500 times.
|
15499023 | if (m_psi_locker != nullptr) { |
| 3037 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1240523 times.
|
1240523 | assert(m_psi_batch_mode == PSI_BATCH_MODE_STARTED); |
| 3038 | 1240523 | PSI_TABLE_CALL(end_table_io_wait)(m_psi_locker, m_psi_numrows); | |
| 3039 | 1240523 | m_psi_locker = nullptr; | |
| 3040 | } | ||
| 3041 | 15499023 | m_psi_batch_mode = PSI_BATCH_MODE_NONE; | |
| 3042 | #endif | ||
| 3043 | 15499023 | } | |
| 3044 | |||
| 3045 | 107717800 | PSI_table_share *handler::ha_table_share_psi(const TABLE_SHARE *share) const { | |
| 3046 | 107717800 | return share->m_psi; | |
| 3047 | } | ||
| 3048 | |||
| 3049 | /* | ||
| 3050 | Open database handler object. | ||
| 3051 | |||
| 3052 | Used for opening tables. The name will be the name of the file. | ||
| 3053 | A table is opened when it needs to be opened. For instance | ||
| 3054 | when a request comes in for a select on the table (tables are not | ||
| 3055 | open and closed for each request, they are cached). | ||
| 3056 | |||
| 3057 | The server opens all tables by calling ha_open() which then calls | ||
| 3058 | the handler specific open(). | ||
| 3059 | |||
| 3060 | Try O_RDONLY if cannot open as O_RDWR. Don't wait for locks if not | ||
| 3061 | HA_OPEN_WAIT_IF_LOCKED is set | ||
| 3062 | |||
| 3063 | @param [out] table_arg Table structure. | ||
| 3064 | @param name Full path of table name. | ||
| 3065 | @param mode Open mode flags. | ||
| 3066 | @param test_if_locked ? | ||
| 3067 | @param table_def dd::Table object describing table | ||
| 3068 | being open. Can be NULL for temporary | ||
| 3069 | tables created by optimizer. | ||
| 3070 | |||
| 3071 | @retval >0 Error. | ||
| 3072 | @retval 0 Success. | ||
| 3073 | */ | ||
| 3074 | |||
| 3075 | 5226484 | int handler::ha_open(TABLE *table_arg, const char *name, int mode, | |
| 3076 | int test_if_locked, const dd::Table *table_def) { | ||
| 3077 | int error; | ||
| 3078 |
1/2✓ Branch 0 taken 5226500 times.
✗ Branch 1 not taken.
|
5226484 | DBUG_TRACE; |
| 3079 |
5/8✓ Branch 0 taken 5226492 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5226499 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 58 times.
✓ Branch 5 taken 5226441 times.
✓ Branch 6 taken 57 times.
✗ Branch 7 not taken.
|
5226500 | DBUG_PRINT("enter", |
| 3080 | ("name: %s db_type: %d db_stat: %d mode: %d lock_test: %d", | ||
| 3081 | name, ht->db_type, table_arg->db_stat, mode, test_if_locked)); | ||
| 3082 | |||
| 3083 | 5226498 | table = table_arg; | |
| 3084 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5226498 times.
|
5226498 | assert(table->s == table_share); |
| 3085 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5226498 times.
|
5226498 | assert(m_lock_type == F_UNLCK); |
| 3086 |
5/8✓ Branch 0 taken 5226495 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5226498 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 56 times.
✓ Branch 5 taken 5226442 times.
✓ Branch 6 taken 55 times.
✗ Branch 7 not taken.
|
5226498 | DBUG_PRINT("info", ("old m_lock_type: %d F_UNLCK %d", m_lock_type, F_UNLCK)); |
| 3087 | 10452994 | MEM_ROOT *mem_root = (test_if_locked & HA_OPEN_TMP_TABLE) | |
| 3088 |
2/2✓ Branch 0 taken 600236 times.
✓ Branch 1 taken 4626261 times.
|
5226497 | ? &table->s->mem_root |
| 3089 | 4626261 | : &table->mem_root; | |
| 3090 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5226489 times.
|
5226497 | assert(alloc_root_inited(mem_root)); |
| 3091 | |||
| 3092 |
2/2✓ Branch 0 taken 438583 times.
✓ Branch 1 taken 4787906 times.
|
5226489 | if (cloned) { |
| 3093 |
4/6✓ Branch 0 taken 438581 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 438581 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 438581 times.
✗ Branch 5 not taken.
|
438583 | DEBUG_SYNC(ha_thd(), "start_handler_ha_open_cloned"); |
| 3094 | } | ||
| 3095 | |||
| 3096 |
3/4✓ Branch 0 taken 5226497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 267 times.
✓ Branch 3 taken 5226230 times.
|
5226489 | if ((error = open(name, mode, test_if_locked, table_def))) { |
| 3097 |
2/6✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 267 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
267 | if ((error == EACCES || error == EROFS) && mode == O_RDWR && |
| 3098 | ✗ | (table->db_stat & HA_TRY_READ_ONLY)) { | |
| 3099 | ✗ | table->db_stat |= HA_READ_ONLY; | |
| 3100 | ✗ | error = open(name, O_RDONLY, test_if_locked, table_def); | |
| 3101 | } | ||
| 3102 | } | ||
| 3103 |
2/2✓ Branch 0 taken 267 times.
✓ Branch 1 taken 5226230 times.
|
5226497 | if (error) { |
| 3104 |
1/2✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
|
267 | set_my_errno(error); /* Safeguard */ |
| 3105 |
3/8✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 267 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 267 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
267 | DBUG_PRINT("error", ("error: %d errno: %d", error, errno)); |
| 3106 | } else { | ||
| 3107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5226230 times.
|
5226230 | assert(m_psi == nullptr); |
| 3108 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5226230 times.
|
5226230 | assert(table_share != nullptr); |
| 3109 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 3110 |
1/2✓ Branch 0 taken 5226232 times.
✗ Branch 1 not taken.
|
5226230 | PSI_table_share *share_psi = ha_table_share_psi(table_share); |
| 3111 |
1/2✓ Branch 0 taken 5226233 times.
✗ Branch 1 not taken.
|
5226232 | m_psi = PSI_TABLE_CALL(open_table)(share_psi, this); |
| 3112 | #endif | ||
| 3113 | |||
| 3114 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 5226214 times.
|
5226233 | if (table->s->db_options_in_use & HA_OPTION_READ_ONLY_DATA) |
| 3115 | 19 | table->db_stat |= HA_READ_ONLY; | |
| 3116 |
1/2✓ Branch 0 taken 5226228 times.
✗ Branch 1 not taken.
|
5226233 | (void)extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL |
| 3117 | |||
| 3118 | /* ref is already allocated for us if we're called from handler::clone() */ | ||
| 3119 |
5/8✓ Branch 0 taken 4787648 times.
✓ Branch 1 taken 438580 times.
✓ Branch 2 taken 4787650 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4787650 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5226230 times.
|
5226228 | if (!ref && !(ref = (uchar *)mem_root->Alloc(ALIGN_SIZE(ref_length) * 2))) { |
| 3120 | ✗ | ha_close(); | |
| 3121 | ✗ | error = HA_ERR_OUT_OF_MEM; | |
| 3122 | } else | ||
| 3123 | 5226230 | dup_ref = ref + ALIGN_SIZE(ref_length); | |
| 3124 | |||
| 3125 | // Give the table a defined starting cursor, even if it never actually seeks | ||
| 3126 | // or writes. This is important for things like weedout on const tables | ||
| 3127 | // (which is a nonsensical combination, but can happen). | ||
| 3128 | 5226230 | memset(ref, 0, ref_length); | |
| 3129 |
1/2✓ Branch 0 taken 5226228 times.
✗ Branch 1 not taken.
|
5226230 | cached_table_flags = table_flags(); |
| 3130 | } | ||
| 3131 | |||
| 3132 |
2/2✓ Branch 0 taken 1465 times.
✓ Branch 1 taken 5225032 times.
|
5226495 | if (unlikely(opt_userstat)) { |
| 3133 | 1465 | rows_read = rows_changed = 0; | |
| 3134 | 1465 | memset(index_rows_read, 0, sizeof(index_rows_read)); | |
| 3135 | } | ||
| 3136 | |||
| 3137 | 5226500 | return error; | |
| 3138 | 5226497 | } | |
| 3139 | |||
| 3140 | /** | ||
| 3141 | Close handler. | ||
| 3142 | |||
| 3143 | Called from sql_base.cc, sql_select.cc, and table.cc. | ||
| 3144 | In sql_select.cc it is only used to close up temporary tables or during | ||
| 3145 | the process where a temporary table is converted over to being a | ||
| 3146 | myisam table. | ||
| 3147 | For sql_base.cc look at close_data_tables(). | ||
| 3148 | |||
| 3149 | @return Operation status | ||
| 3150 | @retval 0 Success | ||
| 3151 | @retval != 0 Error (error code returned) | ||
| 3152 | */ | ||
| 3153 | |||
| 3154 | 4511446 | int handler::ha_close(void) { | |
| 3155 |
1/2✓ Branch 0 taken 4511451 times.
✗ Branch 1 not taken.
|
4511446 | DBUG_TRACE; |
| 3156 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 3157 |
1/2✓ Branch 0 taken 4511451 times.
✗ Branch 1 not taken.
|
4511451 | PSI_TABLE_CALL(close_table)(table_share, m_psi); |
| 3158 | 4511451 | m_psi = nullptr; /* instrumentation handle, invalid after close_table() */ | |
| 3159 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4511451 times.
|
4511451 | assert(m_psi_batch_mode == PSI_BATCH_MODE_NONE); |
| 3160 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4511451 times.
|
4511451 | assert(m_psi_locker == nullptr); |
| 3161 | #endif | ||
| 3162 | // TODO: set table= NULL to mark the handler as closed? | ||
| 3163 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4511451 times.
|
4511451 | assert(m_psi == nullptr); |
| 3164 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4511451 times.
|
4511451 | assert(m_lock_type == F_UNLCK); |
| 3165 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4511451 times.
|
4511451 | assert(inited == NONE); |
| 3166 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 4511399 times.
|
4511451 | if (m_unique) { |
| 3167 | // It's allocated on memroot and will be freed along with it | ||
| 3168 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | m_unique->cleanup(); |
| 3169 | 52 | m_unique = nullptr; | |
| 3170 | } | ||
| 3171 |
1/2✓ Branch 0 taken 4511451 times.
✗ Branch 1 not taken.
|
9022902 | return close(); |
| 3172 | 4511451 | } | |
| 3173 | |||
| 3174 | /** | ||
| 3175 | Initialize use of index. | ||
| 3176 | |||
| 3177 | @param idx Index to use | ||
| 3178 | @param sorted Use sorted order | ||
| 3179 | |||
| 3180 | @return Operation status | ||
| 3181 | @retval 0 Success | ||
| 3182 | @retval != 0 Error (error code returned) | ||
| 3183 | */ | ||
| 3184 | |||
| 3185 | 72291445 | int handler::ha_index_init(uint idx, bool sorted) { | |
| 3186 |
2/4✓ Branch 0 taken 72291658 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 72291658 times.
|
72291445 | DBUG_EXECUTE_IF("ha_index_init_fail", return HA_ERR_TABLE_DEF_CHANGED;); |
| 3187 | int result; | ||
| 3188 |
1/2✓ Branch 0 taken 72291757 times.
✗ Branch 1 not taken.
|
72291658 | DBUG_TRACE; |
| 3189 |
3/4✓ Branch 0 taken 72241300 times.
✓ Branch 1 taken 50457 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 72241300 times.
|
72291757 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3190 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72291757 times.
|
72291757 | assert(inited == NONE); |
| 3191 |
3/4✓ Branch 0 taken 72291687 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72291666 times.
✓ Branch 3 taken 21 times.
|
72291757 | if (!(result = index_init(idx, sorted))) inited = INDEX; |
| 3192 | 72291687 | mrr_have_range = false; | |
| 3193 | 72291687 | end_range = nullptr; | |
| 3194 | 72291687 | return result; | |
| 3195 | 72291687 | } | |
| 3196 | |||
| 3197 | /** | ||
| 3198 | End use of index. | ||
| 3199 | |||
| 3200 | @return Operation status | ||
| 3201 | @retval 0 Success | ||
| 3202 | @retval != 0 Error (error code returned) | ||
| 3203 | */ | ||
| 3204 | |||
| 3205 | 72291720 | int handler::ha_index_end() { | |
| 3206 |
1/2✓ Branch 0 taken 72291738 times.
✗ Branch 1 not taken.
|
72291720 | DBUG_TRACE; |
| 3207 | /* SQL HANDLER function can call this without having it locked. */ | ||
| 3208 |
5/6✓ Branch 0 taken 72291565 times.
✓ Branch 1 taken 173 times.
✓ Branch 2 taken 72241125 times.
✓ Branch 3 taken 50440 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 72241125 times.
|
72291738 | assert(table->open_by_handler || table_share->tmp_table != NO_TMP_TABLE || |
| 3209 | m_lock_type != F_UNLCK); | ||
| 3210 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72291738 times.
|
72291738 | assert(inited == INDEX); |
| 3211 | 72291738 | inited = NONE; | |
| 3212 | 72291738 | end_range = nullptr; | |
| 3213 | 72291738 | m_record_buffer = nullptr; | |
| 3214 |
3/4✓ Branch 0 taken 495 times.
✓ Branch 1 taken 72291243 times.
✓ Branch 2 taken 495 times.
✗ Branch 3 not taken.
|
72291738 | if (m_unique) m_unique->reset(false); |
| 3215 |
1/2✓ Branch 0 taken 72291736 times.
✗ Branch 1 not taken.
|
144583478 | return index_end(); |
| 3216 | 72291736 | } | |
| 3217 | |||
| 3218 | /** | ||
| 3219 | Initialize table for random read or scan. | ||
| 3220 | |||
| 3221 | @param scan if true: Initialize for random scans through rnd_next() | ||
| 3222 | if false: Initialize for random reads through rnd_pos() | ||
| 3223 | |||
| 3224 | @return Operation status | ||
| 3225 | @retval 0 Success | ||
| 3226 | @retval != 0 Error (error code returned) | ||
| 3227 | */ | ||
| 3228 | |||
| 3229 | 15952051 | int handler::ha_rnd_init(bool scan) { | |
| 3230 |
2/4✓ Branch 0 taken 15952052 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15952052 times.
|
15952051 | DBUG_EXECUTE_IF("ha_rnd_init_fail", return HA_ERR_TABLE_DEF_CHANGED;); |
| 3231 | int result; | ||
| 3232 |
1/2✓ Branch 0 taken 15952053 times.
✗ Branch 1 not taken.
|
15952052 | DBUG_TRACE; |
| 3233 |
3/4✓ Branch 0 taken 12989811 times.
✓ Branch 1 taken 2962242 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12989811 times.
|
15952053 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3234 |
4/6✓ Branch 0 taken 2297165 times.
✓ Branch 1 taken 13654888 times.
✓ Branch 2 taken 2297165 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2297165 times.
✗ Branch 5 not taken.
|
15952053 | assert(inited == NONE || (inited == RND && scan)); |
| 3235 |
6/6✓ Branch 0 taken 5135564 times.
✓ Branch 1 taken 10816489 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5135561 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 15952050 times.
|
15952053 | if (scan && is_using_prohibited_gap_locks(table, false)) { |
| 3236 | 2 | return HA_ERR_LOCK_DEADLOCK; | |
| 3237 | } | ||
| 3238 |
3/4✓ Branch 0 taken 15952046 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 15952045 times.
|
15952050 | inited = (result = rnd_init(scan)) ? NONE : RND; |
| 3239 | 15952046 | end_range = nullptr; | |
| 3240 | 15952046 | return result; | |
| 3241 | 15952048 | } | |
| 3242 | |||
| 3243 | /** | ||
| 3244 | End use of random access. | ||
| 3245 | |||
| 3246 | @return Operation status | ||
| 3247 | @retval 0 Success | ||
| 3248 | @retval != 0 Error (error code returned) | ||
| 3249 | */ | ||
| 3250 | |||
| 3251 | 13654808 | int handler::ha_rnd_end() { | |
| 3252 |
1/2✓ Branch 0 taken 13654809 times.
✗ Branch 1 not taken.
|
13654808 | DBUG_TRACE; |
| 3253 | /* SQL HANDLER function can call this without having it locked. */ | ||
| 3254 |
5/6✓ Branch 0 taken 13654641 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 12940024 times.
✓ Branch 3 taken 714617 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12940024 times.
|
13654809 | assert(table->open_by_handler || table_share->tmp_table != NO_TMP_TABLE || |
| 3255 | m_lock_type != F_UNLCK); | ||
| 3256 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13654809 times.
|
13654809 | assert(inited == RND); |
| 3257 | 13654809 | inited = NONE; | |
| 3258 | 13654809 | end_range = nullptr; | |
| 3259 | 13654809 | m_record_buffer = nullptr; | |
| 3260 |
1/2✓ Branch 0 taken 13654807 times.
✗ Branch 1 not taken.
|
27309616 | return rnd_end(); |
| 3261 | 13654807 | } | |
| 3262 | |||
| 3263 | /** | ||
| 3264 | Read next row via random scan. | ||
| 3265 | |||
| 3266 | @param buf Buffer to read the row into | ||
| 3267 | |||
| 3268 | @return Operation status | ||
| 3269 | @retval 0 Success | ||
| 3270 | @retval != 0 Error (error code returned) | ||
| 3271 | */ | ||
| 3272 | |||
| 3273 | 531538418 | int handler::ha_rnd_next(uchar *buf) { | |
| 3274 | int result; | ||
| 3275 |
3/4✓ Branch 0 taken 531538790 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 531538789 times.
|
531538418 | DBUG_EXECUTE_IF("ha_rnd_next_deadlock", return HA_ERR_LOCK_DEADLOCK;); |
| 3276 |
1/2✓ Branch 0 taken 531539527 times.
✗ Branch 1 not taken.
|
531538789 | DBUG_TRACE; |
| 3277 |
3/4✓ Branch 0 taken 415653600 times.
✓ Branch 1 taken 115885927 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 415653600 times.
|
531539527 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3278 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 531539527 times.
|
531539527 | assert(inited == RND); |
| 3279 | |||
| 3280 | // Set status for the need to update generated fields | ||
| 3281 | 531539527 | m_update_generated_read_fields = table->has_gcol(); | |
| 3282 | |||
| 3283 |
19/27✓ Branch 0 taken 80304199 times.
✓ Branch 1 taken 451235397 times.
✓ Branch 2 taken 12166611 times.
✓ Branch 3 taken 274664 times.
✓ Branch 4 taken 67862924 times.
✓ Branch 5 taken 12166611 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12166599 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12165534 times.
✓ Branch 10 taken 1065 times.
✓ Branch 11 taken 12165533 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 274664 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 274664 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 259016 times.
✓ Branch 18 taken 15648 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 67862924 times.
✓ Branch 21 taken 67861867 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 67618755 times.
✓ Branch 24 taken 243112 times.
✓ Branch 25 taken 451235541 times.
✗ Branch 26 not taken.
|
531539596 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, MAX_KEY, result, |
| 3284 | { result = rnd_next(buf); }) | ||
| 3285 |
4/4✓ Branch 0 taken 524964238 times.
✓ Branch 1 taken 6574432 times.
✓ Branch 2 taken 1025662 times.
✓ Branch 3 taken 523938576 times.
|
531538670 | if (!result && m_update_generated_read_fields) { |
| 3286 |
1/2✓ Branch 0 taken 1025662 times.
✗ Branch 1 not taken.
|
1025662 | result = update_generated_read_fields(buf, table); |
| 3287 | 1025662 | m_update_generated_read_fields = false; | |
| 3288 | } | ||
| 3289 | 531538670 | table->set_row_status_from_handler(result); | |
| 3290 | |||
| 3291 |
2/2✓ Branch 0 taken 524964204 times.
✓ Branch 1 taken 6575323 times.
|
531539505 | if (likely(!result)) { |
| 3292 | 524964204 | update_index_stats(active_index); | |
| 3293 | } | ||
| 3294 | |||
| 3295 | 531539459 | return result; | |
| 3296 | 531539459 | } | |
| 3297 | |||
| 3298 | /** | ||
| 3299 | Read row via random scan from position. | ||
| 3300 | |||
| 3301 | @param[out] buf Buffer to read the row into | ||
| 3302 | @param pos Position from position() call | ||
| 3303 | |||
| 3304 | @return Operation status | ||
| 3305 | @retval 0 Success | ||
| 3306 | @retval != 0 Error (error code returned) | ||
| 3307 | */ | ||
| 3308 | |||
| 3309 | 23935096 | int handler::ha_rnd_pos(uchar *buf, uchar *pos) { | |
| 3310 | int result; | ||
| 3311 |
1/2✓ Branch 0 taken 23935101 times.
✗ Branch 1 not taken.
|
23935096 | DBUG_TRACE; |
| 3312 |
3/4✓ Branch 0 taken 1490188 times.
✓ Branch 1 taken 22444913 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1490188 times.
|
23935101 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3313 | /* TODO: Find out how to solve ha_rnd_pos when finding duplicate update. */ | ||
| 3314 | /* assert(inited == RND); */ | ||
| 3315 | |||
| 3316 | // Set status for the need to update generated fields | ||
| 3317 | 23935101 | m_update_generated_read_fields = table->has_gcol(); | |
| 3318 | |||
| 3319 |
16/27✓ Branch 0 taken 1459567 times.
✓ Branch 1 taken 22475534 times.
✓ Branch 2 taken 950554 times.
✓ Branch 3 taken 99707 times.
✓ Branch 4 taken 409306 times.
✓ Branch 5 taken 950554 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 950554 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 950554 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 950554 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 99707 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 99707 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 99707 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 409306 times.
✓ Branch 21 taken 409306 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 409306 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 22475534 times.
✗ Branch 26 not taken.
|
23935101 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, MAX_KEY, result, |
| 3320 | { result = rnd_pos(buf, pos); }) | ||
| 3321 |
4/4✓ Branch 0 taken 23935008 times.
✓ Branch 1 taken 93 times.
✓ Branch 2 taken 9278 times.
✓ Branch 3 taken 23925730 times.
|
23935101 | if (!result && m_update_generated_read_fields) { |
| 3322 |
1/2✓ Branch 0 taken 9278 times.
✗ Branch 1 not taken.
|
9278 | result = update_generated_read_fields(buf, table); |
| 3323 | 9278 | m_update_generated_read_fields = false; | |
| 3324 | } | ||
| 3325 | 23935101 | table->set_row_status_from_handler(result); | |
| 3326 | 23935101 | return result; | |
| 3327 | 23935101 | } | |
| 3328 | |||
| 3329 | ✗ | FT_INFO *handler::ft_init_ext(uint flags [[maybe_unused]], | |
| 3330 | uint inx [[maybe_unused]], | ||
| 3331 | String *key [[maybe_unused]]) { | ||
| 3332 | ✗ | my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0)); | |
| 3333 | ✗ | return nullptr; | |
| 3334 | } | ||
| 3335 | |||
| 3336 | 52366 | int handler::ha_ft_read(uchar *buf) { | |
| 3337 | int result; | ||
| 3338 |
1/2✓ Branch 0 taken 52366 times.
✗ Branch 1 not taken.
|
52366 | DBUG_TRACE; |
| 3339 | |||
| 3340 | // Set status for the need to update generated fields | ||
| 3341 | 52366 | m_update_generated_read_fields = table->has_gcol(); | |
| 3342 | |||
| 3343 |
1/2✓ Branch 0 taken 52366 times.
✗ Branch 1 not taken.
|
52366 | result = ft_read(buf); |
| 3344 |
4/4✓ Branch 0 taken 50280 times.
✓ Branch 1 taken 2086 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 50258 times.
|
52366 | if (!result && m_update_generated_read_fields) { |
| 3345 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | result = update_generated_read_fields(buf, table); |
| 3346 | 22 | m_update_generated_read_fields = false; | |
| 3347 | } | ||
| 3348 | 52366 | table->set_row_status_from_handler(result); | |
| 3349 | 52366 | return result; | |
| 3350 | 52366 | } | |
| 3351 | |||
| 3352 | 205 | int handler::ha_sample_init(void *&scan_ctx, double sampling_percentage, | |
| 3353 | int sampling_seed, | ||
| 3354 | enum_sampling_method sampling_method, | ||
| 3355 | const bool tablesample) { | ||
| 3356 |
1/2✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
|
205 | DBUG_TRACE; |
| 3357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
|
205 | assert(sampling_percentage >= 0.0); |
| 3358 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
|
205 | assert(sampling_percentage <= 100.0); |
| 3359 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
|
205 | assert(inited == NONE); |
| 3360 | |||
| 3361 | // Initialise the random number generator. | ||
| 3362 |
1/2✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
|
205 | m_random_number_engine.seed(sampling_seed); |
| 3363 | 205 | m_sampling_percentage = sampling_percentage; | |
| 3364 | |||
| 3365 |
1/2✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
|
205 | int result = sample_init(scan_ctx, sampling_percentage, sampling_seed, |
| 3366 | sampling_method, tablesample); | ||
| 3367 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 204 times.
|
205 | inited = (result != 0) ? NONE : SAMPLING; |
| 3368 | 205 | return result; | |
| 3369 | 205 | } | |
| 3370 | |||
| 3371 | 204 | int handler::ha_sample_end(void *scan_ctx) { | |
| 3372 |
1/2✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
|
204 | DBUG_TRACE; |
| 3373 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
|
204 | assert(inited == SAMPLING); |
| 3374 | 204 | inited = NONE; | |
| 3375 |
1/2✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
|
204 | int result = sample_end(scan_ctx); |
| 3376 | 204 | return result; | |
| 3377 | 204 | } | |
| 3378 | |||
| 3379 | 41125 | int handler::ha_sample_next(void *scan_ctx, uchar *buf) { | |
| 3380 |
1/2✓ Branch 0 taken 41125 times.
✗ Branch 1 not taken.
|
41125 | DBUG_TRACE; |
| 3381 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 41125 times.
|
41125 | assert(inited == SAMPLING); |
| 3382 | |||
| 3383 |
2/2✓ Branch 0 taken 100 times.
✓ Branch 1 taken 41025 times.
|
41125 | if (m_sampling_percentage == 0.0) return HA_ERR_END_OF_FILE; |
| 3384 | |||
| 3385 | 41025 | m_update_generated_read_fields = table->has_gcol(); | |
| 3386 | |||
| 3387 | int result; | ||
| 3388 |
8/27✓ Branch 0 taken 40925 times.
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 40925 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 40925 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 40925 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 40925 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 40925 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 100 times.
✗ Branch 26 not taken.
|
41025 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, MAX_KEY, result, |
| 3389 | { result = sample_next(scan_ctx, buf); }) | ||
| 3390 | |||
| 3391 |
4/4✓ Branch 0 taken 40824 times.
✓ Branch 1 taken 201 times.
✓ Branch 2 taken 647 times.
✓ Branch 3 taken 40177 times.
|
41025 | if (result == 0 && m_update_generated_read_fields) { |
| 3392 |
1/2✓ Branch 0 taken 647 times.
✗ Branch 1 not taken.
|
647 | result = update_generated_read_fields(buf, table); |
| 3393 | 647 | m_update_generated_read_fields = false; | |
| 3394 | } | ||
| 3395 | 41025 | table->set_row_status_from_handler(result); | |
| 3396 | |||
| 3397 |
2/2✓ Branch 0 taken 40824 times.
✓ Branch 1 taken 201 times.
|
41025 | if (likely(!result)) { |
| 3398 | 40824 | update_index_stats(active_index); | |
| 3399 | } | ||
| 3400 | |||
| 3401 | 41025 | return result; | |
| 3402 | 41125 | } | |
| 3403 | |||
| 3404 | 2 | int handler::sample_init(void *&scan_ctx [[maybe_unused]], double, int, | |
| 3405 | enum_sampling_method, const bool) { | ||
| 3406 | 2 | return rnd_init(true); | |
| 3407 | } | ||
| 3408 | |||
| 3409 | 2 | int handler::sample_end(void *scan_ctx [[maybe_unused]]) { return rnd_end(); } | |
| 3410 | |||
| 3411 | 100 | int handler::sample_next(void *scan_ctx [[maybe_unused]], uchar *buf) { | |
| 3412 | // Temporary set inited to RND, since we are calling rnd_next(). | ||
| 3413 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | int res = rnd_next(buf); |
| 3414 | |||
| 3415 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | std::uniform_real_distribution<double> rnd(0.0, 1.0); |
| 3416 |
4/8✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 100 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 100 times.
|
100 | while (!res && rnd(m_random_number_engine) > (m_sampling_percentage / 100.0)) |
| 3417 | ✗ | res = rnd_next(buf); | |
| 3418 | |||
| 3419 | 100 | return res; | |
| 3420 | } | ||
| 3421 | |||
| 3422 | 1153 | int handler::records(ha_rows *num_rows) { | |
| 3423 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1152 times.
|
1153 | if (ha_table_flags() & HA_COUNT_ROWS_INSTANT) { |
| 3424 | 1 | *num_rows = stats.records; | |
| 3425 | 1 | return 0; | |
| 3426 | } | ||
| 3427 | |||
| 3428 | 1152 | int error = 0; | |
| 3429 | 1152 | ha_rows rows = 0; | |
| 3430 | 1152 | start_psi_batch_mode(); | |
| 3431 | |||
| 3432 |
1/2✓ Branch 0 taken 1152 times.
✗ Branch 1 not taken.
|
1152 | if (!(error = ha_rnd_init(true))) { |
| 3433 |
2/2✓ Branch 0 taken 940648 times.
✓ Branch 1 taken 1 times.
|
940649 | while (!table->in_use->killed) { |
| 3434 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 940647 times.
|
940648 | DBUG_EXECUTE_IF("bug28079850", table->in_use->killed = THD::KILL_QUERY;); |
| 3435 |
2/2✓ Branch 0 taken 1314 times.
✓ Branch 1 taken 939334 times.
|
940648 | if ((error = ha_rnd_next(table->record[0]))) { |
| 3436 |
2/2✓ Branch 0 taken 163 times.
✓ Branch 1 taken 1151 times.
|
1314 | if (error == HA_ERR_RECORD_DELETED) |
| 3437 | 163 | continue; | |
| 3438 | else | ||
| 3439 | 1151 | break; | |
| 3440 | } | ||
| 3441 | 939334 | ++rows; | |
| 3442 | } | ||
| 3443 | } | ||
| 3444 | |||
| 3445 | 1152 | *num_rows = rows; | |
| 3446 | 1152 | end_psi_batch_mode(); | |
| 3447 | 1152 | int ha_rnd_end_error = 0; | |
| 3448 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1149 times.
|
1152 | if (error != HA_ERR_END_OF_FILE) *num_rows = HA_POS_ERROR; |
| 3449 | |||
| 3450 | // Call ha_rnd_end() only if only if handler has been initialized. | ||
| 3451 |
3/6✓ Branch 0 taken 1152 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1152 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1152 times.
|
1152 | if (inited && (ha_rnd_end_error = ha_rnd_end())) *num_rows = HA_POS_ERROR; |
| 3452 | |||
| 3453 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1149 times.
|
1152 | return (error != HA_ERR_END_OF_FILE) ? error : ha_rnd_end_error; |
| 3454 | } | ||
| 3455 | |||
| 3456 | 21 | int handler::records_from_index(ha_rows *num_rows, uint index) { | |
| 3457 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 18 times.
|
21 | if (ha_table_flags() & HA_COUNT_ROWS_INSTANT) { |
| 3458 | 3 | *num_rows = stats.records; | |
| 3459 | 3 | return 0; | |
| 3460 | } | ||
| 3461 | |||
| 3462 | 18 | int error = 0; | |
| 3463 | 18 | ha_rows rows = 0; | |
| 3464 | 18 | uchar *buf = table->record[0]; | |
| 3465 | 18 | start_psi_batch_mode(); | |
| 3466 | |||
| 3467 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | if (!(error = ha_index_init(index, false))) { |
| 3468 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (!(error = ha_index_first(buf))) { |
| 3469 | ✗ | rows = 1; | |
| 3470 | |||
| 3471 | ✗ | while (!table->in_use->killed) { | |
| 3472 | ✗ | DBUG_EXECUTE_IF("bug28079850", | |
| 3473 | table->in_use->killed = THD::KILL_QUERY;); | ||
| 3474 | ✗ | if ((error = ha_index_next(buf))) { | |
| 3475 | ✗ | if (error == HA_ERR_RECORD_DELETED) | |
| 3476 | ✗ | continue; | |
| 3477 | else | ||
| 3478 | ✗ | break; | |
| 3479 | } | ||
| 3480 | ✗ | ++rows; | |
| 3481 | } | ||
| 3482 | } | ||
| 3483 | } | ||
| 3484 | |||
| 3485 | 18 | *num_rows = rows; | |
| 3486 | 18 | end_psi_batch_mode(); | |
| 3487 | 18 | int ha_index_end_error = 0; | |
| 3488 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (error != HA_ERR_END_OF_FILE) *num_rows = HA_POS_ERROR; |
| 3489 | |||
| 3490 | // Call ha_index_end() only if handler has been initialized. | ||
| 3491 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
|
18 | if (inited && (ha_index_end_error = ha_index_end())) *num_rows = HA_POS_ERROR; |
| 3492 | |||
| 3493 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | return (error != HA_ERR_END_OF_FILE) ? error : ha_index_end_error; |
| 3494 | } | ||
| 3495 | |||
| 3496 | 34125 | int handler::handle_records_error(int error, ha_rows *num_rows) { | |
| 3497 | // If query was killed set the error since not all storage engines do it. | ||
| 3498 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 34123 times.
|
34125 | if (table->in_use->killed) { |
| 3499 | 2 | *num_rows = HA_POS_ERROR; | |
| 3500 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (error == 0) error = HA_ERR_QUERY_INTERRUPTED; |
| 3501 | } | ||
| 3502 | |||
| 3503 |
3/4✓ Branch 0 taken 73 times.
✓ Branch 1 taken 34052 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 73 times.
|
34125 | if (error != 0) assert(*num_rows == HA_POS_ERROR); |
| 3504 |
3/4✓ Branch 0 taken 73 times.
✓ Branch 1 taken 34052 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 73 times.
|
34125 | if (*num_rows == HA_POS_ERROR) assert(error != 0); |
| 3505 |
2/2✓ Branch 0 taken 73 times.
✓ Branch 1 taken 34052 times.
|
34125 | if (error != 0) { |
| 3506 | /* | ||
| 3507 | ha_innobase::records may have rolled back internally. | ||
| 3508 | In this case, thd_mark_transaction_to_rollback() will have been called. | ||
| 3509 | For the errors below, we need to abort right away. | ||
| 3510 | */ | ||
| 3511 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 40 times.
|
73 | switch (error) { |
| 3512 | 33 | case HA_ERR_LOCK_DEADLOCK: | |
| 3513 | case HA_ERR_LOCK_TABLE_FULL: | ||
| 3514 | case HA_ERR_LOCK_WAIT_TIMEOUT: | ||
| 3515 | case HA_ERR_QUERY_INTERRUPTED: | ||
| 3516 | 33 | print_error(error, MYF(0)); | |
| 3517 | 33 | return error; | |
| 3518 | 40 | default: | |
| 3519 | 40 | return error; | |
| 3520 | } | ||
| 3521 | } | ||
| 3522 | 34052 | return 0; | |
| 3523 | } | ||
| 3524 | |||
| 3525 | /** | ||
| 3526 | Read [part of] row via [part of] index. | ||
| 3527 | @param[out] buf buffer where store the data | ||
| 3528 | @param key Key to search for | ||
| 3529 | @param keypart_map Which part of key to use | ||
| 3530 | @param find_flag Direction/condition on key usage | ||
| 3531 | |||
| 3532 | @returns Operation status | ||
| 3533 | @retval 0 Success (found a record, and function has | ||
| 3534 | set table status to "has row") | ||
| 3535 | @retval HA_ERR_END_OF_FILE Row not found (function has set table status | ||
| 3536 | to "no row"). End of index passed. | ||
| 3537 | @retval HA_ERR_KEY_NOT_FOUND Row not found (function has set table status | ||
| 3538 | to "no row"). Index cursor positioned. | ||
| 3539 | @retval != 0 Error | ||
| 3540 | |||
| 3541 | @note Positions an index cursor to the index specified in the handle. | ||
| 3542 | Fetches the row if available. If the key value is null, | ||
| 3543 | begin at the first key of the index. | ||
| 3544 | ha_index_read_map can be restarted without calling index_end on the previous | ||
| 3545 | index scan and without calling ha_index_init. In this case the | ||
| 3546 | ha_index_read_map is on the same index as the previous ha_index_scan. | ||
| 3547 | This is particularly used in conjunction with multi read ranges. | ||
| 3548 | */ | ||
| 3549 | |||
| 3550 | 31772640 | int handler::ha_index_read_map(uchar *buf, const uchar *key, | |
| 3551 | key_part_map keypart_map, | ||
| 3552 | enum ha_rkey_function find_flag) { | ||
| 3553 | int result; | ||
| 3554 |
1/2✓ Branch 0 taken 31772865 times.
✗ Branch 1 not taken.
|
31772640 | DBUG_TRACE; |
| 3555 |
3/4✓ Branch 0 taken 24449712 times.
✓ Branch 1 taken 7323153 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24449712 times.
|
31772865 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3556 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31772865 times.
|
31772865 | assert(inited == INDEX); |
| 3557 |
3/4✓ Branch 0 taken 377296 times.
✓ Branch 1 taken 31395569 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 377296 times.
|
31772865 | assert(!pushed_idx_cond || buf == table->record[0]); |
| 3558 | |||
| 3559 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31772711 times.
|
31772759 | if (is_using_prohibited_gap_locks( |
| 3560 | table, | ||
| 3561 | 31772865 | is_using_full_unique_key(active_index, keypart_map, find_flag))) { | |
| 3562 | ✗ | return HA_ERR_LOCK_DEADLOCK; | |
| 3563 | } | ||
| 3564 | |||
| 3565 | // Set status for the need to update generated fields | ||
| 3566 | 31772711 | m_update_generated_read_fields = table->has_gcol(); | |
| 3567 | |||
| 3568 |
19/27✓ Branch 0 taken 12465462 times.
✓ Branch 1 taken 19307300 times.
✓ Branch 2 taken 11058423 times.
✓ Branch 3 taken 1372011 times.
✓ Branch 4 taken 35028 times.
✓ Branch 5 taken 11058353 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 11058473 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 11057441 times.
✓ Branch 10 taken 1032 times.
✓ Branch 11 taken 11057441 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1372011 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1372011 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1372009 times.
✓ Branch 18 taken 2 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 35028 times.
✓ Branch 21 taken 35028 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 35025 times.
✓ Branch 24 taken 3 times.
✓ Branch 25 taken 19307316 times.
✗ Branch 26 not taken.
|
31772762 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, { |
| 3569 | result = index_read_map(buf, key, keypart_map, find_flag); | ||
| 3570 | }) | ||
| 3571 |
4/4✓ Branch 0 taken 19419216 times.
✓ Branch 1 taken 12353612 times.
✓ Branch 2 taken 12688 times.
✓ Branch 3 taken 19406528 times.
|
31772828 | if (!result && m_update_generated_read_fields) { |
| 3572 |
1/2✓ Branch 0 taken 12688 times.
✗ Branch 1 not taken.
|
12688 | result = update_generated_read_fields(buf, table, active_index); |
| 3573 | 12688 | m_update_generated_read_fields = false; | |
| 3574 | } | ||
| 3575 | // Filter duplicate records from multi-value index read. | ||
| 3576 | // (m_unique != nullptr in case of multi-value index read) | ||
| 3577 | // In case of range scan, duplicate records are filtered in | ||
| 3578 | // multi_range_read_next() | ||
| 3579 |
9/12✓ Branch 0 taken 19419218 times.
✓ Branch 1 taken 12353610 times.
✓ Branch 2 taken 19102288 times.
✓ Branch 3 taken 316930 times.
✓ Branch 4 taken 256 times.
✓ Branch 5 taken 19102032 times.
✓ Branch 6 taken 256 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 256 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 31772828 times.
|
31772828 | if (!result && !mrr_have_range && m_unique != nullptr && filter_dup_records()) |
| 3580 | ✗ | result = HA_ERR_KEY_NOT_FOUND; | |
| 3581 | |||
| 3582 | 31772828 | table->set_row_status_from_handler(result); | |
| 3583 | |||
| 3584 |
2/2✓ Branch 0 taken 19419218 times.
✓ Branch 1 taken 12353675 times.
|
31772889 | if (likely(!result)) { |
| 3585 | 19419218 | update_index_stats(active_index); | |
| 3586 | } | ||
| 3587 | |||
| 3588 | 31772892 | return result; | |
| 3589 | 31772892 | } | |
| 3590 | |||
| 3591 | 487 | int handler::ha_index_read_last_map(uchar *buf, const uchar *key, | |
| 3592 | key_part_map keypart_map) { | ||
| 3593 | int result; | ||
| 3594 |
1/2✓ Branch 0 taken 487 times.
✗ Branch 1 not taken.
|
487 | DBUG_TRACE; |
| 3595 |
2/4✓ Branch 0 taken 487 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 487 times.
|
487 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3596 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 487 times.
|
487 | assert(inited == INDEX); |
| 3597 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 487 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
487 | assert(!pushed_idx_cond || buf == table->record[0]); |
| 3598 | |||
| 3599 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 487 times.
|
487 | if (is_using_prohibited_gap_locks(table, false)) { |
| 3600 | ✗ | return HA_ERR_LOCK_DEADLOCK; | |
| 3601 | } | ||
| 3602 | |||
| 3603 | // Set status for the need to update generated fields | ||
| 3604 | 487 | m_update_generated_read_fields = table->has_gcol(); | |
| 3605 | |||
| 3606 |
5/27✓ Branch 0 taken 487 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 487 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 487 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 487 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 487 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
|
487 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, |
| 3607 | { result = index_read_last_map(buf, key, keypart_map); }) | ||
| 3608 |
4/4✓ Branch 0 taken 457 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 456 times.
|
487 | if (!result && m_update_generated_read_fields) { |
| 3609 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | result = update_generated_read_fields(buf, table, active_index); |
| 3610 | 1 | m_update_generated_read_fields = false; | |
| 3611 | } | ||
| 3612 | 487 | table->set_row_status_from_handler(result); | |
| 3613 | |||
| 3614 |
2/2✓ Branch 0 taken 457 times.
✓ Branch 1 taken 30 times.
|
487 | if (likely(!result)) { |
| 3615 | 457 | update_index_stats(active_index); | |
| 3616 | } | ||
| 3617 | |||
| 3618 | 487 | return result; | |
| 3619 | 487 | } | |
| 3620 | |||
| 3621 | /** | ||
| 3622 | Initializes an index and read it. | ||
| 3623 | |||
| 3624 | @see handler::ha_index_read_map. | ||
| 3625 | */ | ||
| 3626 | |||
| 3627 | 50798784 | int handler::ha_index_read_idx_map(uchar *buf, uint index, const uchar *key, | |
| 3628 | key_part_map keypart_map, | ||
| 3629 | enum ha_rkey_function find_flag) { | ||
| 3630 | int result; | ||
| 3631 |
1/2✓ Branch 0 taken 50799268 times.
✗ Branch 1 not taken.
|
50798784 | DBUG_TRACE; |
| 3632 |
3/4✓ Branch 0 taken 50799160 times.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50799160 times.
|
50799268 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3633 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50799268 times.
|
50799268 | assert(end_range == nullptr); |
| 3634 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 50799268 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
50799268 | assert(!pushed_idx_cond || buf == table->record[0]); |
| 3635 | |||
| 3636 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50798905 times.
|
50799065 | if (is_using_prohibited_gap_locks( |
| 3637 | 50799268 | table, is_using_full_unique_key(index, keypart_map, find_flag))) { | |
| 3638 | ✗ | return HA_ERR_LOCK_DEADLOCK; | |
| 3639 | } | ||
| 3640 | |||
| 3641 | // Set status for the need to update generated fields | ||
| 3642 | 50798905 | m_update_generated_read_fields = table->has_gcol(); | |
| 3643 | |||
| 3644 |
8/27✓ Branch 0 taken 33158 times.
✓ Branch 1 taken 50765921 times.
✓ Branch 2 taken 33158 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 33158 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 33158 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 33158 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 33158 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 50766180 times.
✗ Branch 26 not taken.
|
50799079 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, index, result, { |
| 3645 | result = index_read_idx_map(buf, index, key, keypart_map, find_flag); | ||
| 3646 | }) | ||
| 3647 |
4/4✓ Branch 0 taken 33044825 times.
✓ Branch 1 taken 17754513 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 33044791 times.
|
50799338 | if (!result && m_update_generated_read_fields) { |
| 3648 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | result = update_generated_read_fields(buf, table, index); |
| 3649 | 34 | m_update_generated_read_fields = false; | |
| 3650 | } | ||
| 3651 | 50799338 | table->set_row_status_from_handler(result); | |
| 3652 |
2/2✓ Branch 0 taken 33044832 times.
✓ Branch 1 taken 17754515 times.
|
50799340 | if (likely(!result)) { |
| 3653 | 33044832 | update_index_stats(index); | |
| 3654 | } | ||
| 3655 | 50799356 | return result; | |
| 3656 | 50799356 | } | |
| 3657 | |||
| 3658 | /** | ||
| 3659 | Reads the next row via index. | ||
| 3660 | |||
| 3661 | @param[out] buf Row data | ||
| 3662 | |||
| 3663 | @return Operation status. | ||
| 3664 | @retval 0 Success | ||
| 3665 | @retval HA_ERR_END_OF_FILE Row not found | ||
| 3666 | @retval != 0 Error | ||
| 3667 | */ | ||
| 3668 | |||
| 3669 | 23803110 | int handler::ha_index_next(uchar *buf) { | |
| 3670 | int result; | ||
| 3671 |
1/2✓ Branch 0 taken 23803104 times.
✗ Branch 1 not taken.
|
23803110 | DBUG_TRACE; |
| 3672 |
3/4✓ Branch 0 taken 23760233 times.
✓ Branch 1 taken 42871 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23760233 times.
|
23803104 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3673 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23803104 times.
|
23803104 | assert(inited == INDEX); |
| 3674 |
3/4✓ Branch 0 taken 9007 times.
✓ Branch 1 taken 23794097 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9007 times.
|
23803104 | assert(!pushed_idx_cond || buf == table->record[0]); |
| 3675 | |||
| 3676 | // Set status for the need to update generated fields | ||
| 3677 | 23803104 | m_update_generated_read_fields = table->has_gcol(); | |
| 3678 | |||
| 3679 |
14/27✓ Branch 0 taken 18739609 times.
✓ Branch 1 taken 5063495 times.
✓ Branch 2 taken 5795947 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12943662 times.
✓ Branch 5 taken 5795947 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5795935 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 5239268 times.
✓ Branch 10 taken 556667 times.
✓ Branch 11 taken 5239268 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 12943662 times.
✓ Branch 21 taken 12943662 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 12898054 times.
✓ Branch 24 taken 45608 times.
✓ Branch 25 taken 5063493 times.
✗ Branch 26 not taken.
|
23803104 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, |
| 3680 | { result = index_next(buf); }) | ||
| 3681 |
4/4✓ Branch 0 taken 23276786 times.
✓ Branch 1 taken 526304 times.
✓ Branch 2 taken 215589 times.
✓ Branch 3 taken 23061197 times.
|
23803090 | if (!result && m_update_generated_read_fields) { |
| 3682 |
1/2✓ Branch 0 taken 215589 times.
✗ Branch 1 not taken.
|
215589 | result = update_generated_read_fields(buf, table, active_index); |
| 3683 | 215589 | m_update_generated_read_fields = false; | |
| 3684 | } | ||
| 3685 | // Filter duplicate records from multi-value index read. | ||
| 3686 | // (m_unique != nullptr in case of multi-value index read) | ||
| 3687 | // In case of range scan, duplicate records are filtered in | ||
| 3688 | // multi_range_read_next() | ||
| 3689 |
6/12✓ Branch 0 taken 23276786 times.
✓ Branch 1 taken 526304 times.
✓ Branch 2 taken 20585529 times.
✓ Branch 3 taken 2691257 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 20585529 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 23803090 times.
|
23803090 | if (!result && !mrr_have_range && m_unique != nullptr && filter_dup_records()) |
| 3690 | ✗ | result = HA_ERR_KEY_NOT_FOUND; | |
| 3691 | |||
| 3692 | 23803090 | table->set_row_status_from_handler(result); | |
| 3693 |
2/2✓ Branch 0 taken 23276782 times.
✓ Branch 1 taken 526302 times.
|
23803088 | if (likely(!result)) { |
| 3694 | 23276782 | update_index_stats(active_index); | |
| 3695 | } | ||
| 3696 | |||
| 3697 |
4/6✓ Branch 0 taken 23606087 times.
✓ Branch 1 taken 196996 times.
✓ Branch 2 taken 23606091 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23606100 times.
✗ Branch 5 not taken.
|
23803085 | DEBUG_SYNC(ha_thd(), "handler_ha_index_next_end"); |
| 3698 | |||
| 3699 | 23803094 | return result; | |
| 3700 | 23803096 | } | |
| 3701 | |||
| 3702 | 82571715 | bool handler::is_using_full_key(key_part_map keypart_map, | |
| 3703 | uint actual_key_parts) noexcept { | ||
| 3704 |
2/2✓ Branch 0 taken 50665760 times.
✓ Branch 1 taken 31905955 times.
|
133237475 | return (keypart_map == HA_WHOLE_KEY) || |
| 3705 |
2/2✓ Branch 0 taken 21750699 times.
✓ Branch 1 taken 28915061 times.
|
133237475 | (keypart_map == ((key_part_map(1) << actual_key_parts) - 1)); |
| 3706 | } | ||
| 3707 | |||
| 3708 | 82571732 | bool handler::is_using_full_unique_key( | |
| 3709 | uint index, key_part_map keypart_map, | ||
| 3710 | enum ha_rkey_function find_flag) const noexcept { | ||
| 3711 | return ( | ||
| 3712 |
2/2✓ Branch 0 taken 43551330 times.
✓ Branch 1 taken 10105449 times.
|
136228511 | is_using_full_key(keypart_map, table->key_info[index].actual_key_parts) && |
| 3713 |
2/2✓ Branch 0 taken 53656779 times.
✓ Branch 1 taken 28915035 times.
|
136228593 | find_flag == HA_READ_KEY_EXACT && |
| 3714 |
2/2✓ Branch 0 taken 11109437 times.
✓ Branch 1 taken 32441893 times.
|
43551330 | (index == table->s->primary_key || |
| 3715 |
2/2✓ Branch 0 taken 6998680 times.
✓ Branch 1 taken 4110757 times.
|
93681251 | (table->key_info[index].flags & HA_NOSAME))); |
| 3716 | } | ||
| 3717 | |||
| 3718 | /** | ||
| 3719 | Reads the previous row via index. | ||
| 3720 | |||
| 3721 | @param[out] buf Row data | ||
| 3722 | |||
| 3723 | @return Operation status. | ||
| 3724 | @retval 0 Success | ||
| 3725 | @retval HA_ERR_END_OF_FILE Row not found | ||
| 3726 | @retval != 0 Error | ||
| 3727 | */ | ||
| 3728 | |||
| 3729 | 19456 | int handler::ha_index_prev(uchar *buf) { | |
| 3730 | int result; | ||
| 3731 |
1/2✓ Branch 0 taken 19456 times.
✗ Branch 1 not taken.
|
19456 | DBUG_TRACE; |
| 3732 |
3/4✓ Branch 0 taken 19450 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19450 times.
|
19456 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3733 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19456 times.
|
19456 | assert(inited == INDEX); |
| 3734 |
3/4✓ Branch 0 taken 275 times.
✓ Branch 1 taken 19181 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 275 times.
|
19456 | assert(!pushed_idx_cond || buf == table->record[0]); |
| 3735 | |||
| 3736 | // Set status for the need to update generated fields | ||
| 3737 | 19456 | m_update_generated_read_fields = table->has_gcol(); | |
| 3738 | |||
| 3739 |
13/27✓ Branch 0 taken 19450 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 223 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19227 times.
✓ Branch 5 taken 223 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 223 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 223 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 223 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 19227 times.
✓ Branch 21 taken 19227 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 18254 times.
✓ Branch 24 taken 973 times.
✓ Branch 25 taken 6 times.
✗ Branch 26 not taken.
|
19456 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, |
| 3740 | { result = index_prev(buf); }) | ||
| 3741 |
4/4✓ Branch 0 taken 18473 times.
✓ Branch 1 taken 983 times.
✓ Branch 2 taken 59 times.
✓ Branch 3 taken 18414 times.
|
19456 | if (!result && m_update_generated_read_fields) { |
| 3742 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | result = update_generated_read_fields(buf, table, active_index); |
| 3743 | 59 | m_update_generated_read_fields = false; | |
| 3744 | } | ||
| 3745 | 19456 | table->set_row_status_from_handler(result); | |
| 3746 | |||
| 3747 |
2/2✓ Branch 0 taken 18473 times.
✓ Branch 1 taken 983 times.
|
19456 | if (likely(!result)) { |
| 3748 | 18473 | update_index_stats(active_index); | |
| 3749 | } | ||
| 3750 | |||
| 3751 | 19456 | return result; | |
| 3752 | 19456 | } | |
| 3753 | |||
| 3754 | /** | ||
| 3755 | Reads the first row via index. | ||
| 3756 | |||
| 3757 | @param[out] buf Row data | ||
| 3758 | |||
| 3759 | @return Operation status. | ||
| 3760 | @retval 0 Success | ||
| 3761 | @retval HA_ERR_END_OF_FILE Row not found | ||
| 3762 | @retval != 0 Error | ||
| 3763 | */ | ||
| 3764 | |||
| 3765 | 648816 | int handler::ha_index_first(uchar *buf) { | |
| 3766 | int result; | ||
| 3767 |
1/2✓ Branch 0 taken 648951 times.
✗ Branch 1 not taken.
|
648816 | DBUG_TRACE; |
| 3768 |
3/4✓ Branch 0 taken 648489 times.
✓ Branch 1 taken 462 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 648489 times.
|
648951 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3769 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 648951 times.
|
648951 | assert(inited == INDEX); |
| 3770 |
3/4✓ Branch 0 taken 260 times.
✓ Branch 1 taken 648691 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 260 times.
|
648951 | assert(!pushed_idx_cond || buf == table->record[0]); |
| 3771 | |||
| 3772 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 648825 times.
|
648951 | if (is_using_prohibited_gap_locks(table, false)) { |
| 3773 | ✗ | return HA_ERR_LOCK_DEADLOCK; | |
| 3774 | } | ||
| 3775 | |||
| 3776 | // Set status for the need to update generated fields | ||
| 3777 | 648825 | m_update_generated_read_fields = table->has_gcol(); | |
| 3778 | |||
| 3779 |
18/27✓ Branch 0 taken 77682 times.
✓ Branch 1 taken 571196 times.
✓ Branch 2 taken 27420 times.
✓ Branch 3 taken 50260 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 27420 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 27419 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 26553 times.
✓ Branch 10 taken 866 times.
✓ Branch 11 taken 26553 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 50260 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 50259 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 47325 times.
✓ Branch 18 taken 2934 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 2 times.
✓ Branch 21 taken 2 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 2 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 571258 times.
✗ Branch 26 not taken.
|
648878 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, |
| 3780 | { result = index_first(buf); }) | ||
| 3781 |
4/4✓ Branch 0 taken 533191 times.
✓ Branch 1 taken 115747 times.
✓ Branch 2 taken 689 times.
✓ Branch 3 taken 532502 times.
|
648938 | if (!result && m_update_generated_read_fields) { |
| 3782 |
1/2✓ Branch 0 taken 689 times.
✗ Branch 1 not taken.
|
689 | result = update_generated_read_fields(buf, table, active_index); |
| 3783 | 689 | m_update_generated_read_fields = false; | |
| 3784 | } | ||
| 3785 | // Filter duplicate records from multi-value index read. | ||
| 3786 | // (m_unique != nullptr in case of multi-value index read) | ||
| 3787 | // In case of range scan, duplicate records are filtered in | ||
| 3788 | // multi_range_read_next() | ||
| 3789 |
6/12✓ Branch 0 taken 533194 times.
✓ Branch 1 taken 115744 times.
✓ Branch 2 taken 530009 times.
✓ Branch 3 taken 3185 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 530009 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 648938 times.
|
648938 | if (!result && !mrr_have_range && m_unique != nullptr && filter_dup_records()) |
| 3790 | ✗ | result = HA_ERR_KEY_NOT_FOUND; | |
| 3791 | |||
| 3792 | 648938 | table->set_row_status_from_handler(result); | |
| 3793 | |||
| 3794 |
2/2✓ Branch 0 taken 533200 times.
✓ Branch 1 taken 115749 times.
|
648948 | if (likely(!result)) { |
| 3795 | 533200 | update_index_stats(active_index); | |
| 3796 | } | ||
| 3797 | |||
| 3798 | 648945 | return result; | |
| 3799 | 648945 | } | |
| 3800 | |||
| 3801 | /** | ||
| 3802 | Reads the last row via index. | ||
| 3803 | |||
| 3804 | @param[out] buf Row data | ||
| 3805 | |||
| 3806 | @return Operation status. | ||
| 3807 | @retval 0 Success | ||
| 3808 | @retval HA_ERR_END_OF_FILE Row not found | ||
| 3809 | @retval != 0 Error | ||
| 3810 | */ | ||
| 3811 | |||
| 3812 | 5417 | int handler::ha_index_last(uchar *buf) { | |
| 3813 | int result; | ||
| 3814 |
1/2✓ Branch 0 taken 5417 times.
✗ Branch 1 not taken.
|
5417 | DBUG_TRACE; |
| 3815 |
3/4✓ Branch 0 taken 5415 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5415 times.
|
5417 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3816 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5417 times.
|
5417 | assert(inited == INDEX); |
| 3817 |
3/4✓ Branch 0 taken 55 times.
✓ Branch 1 taken 5362 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55 times.
|
5417 | assert(!pushed_idx_cond || buf == table->record[0]); |
| 3818 | |||
| 3819 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5417 times.
|
5417 | if (is_using_prohibited_gap_locks(table, false)) { |
| 3820 | ✗ | return HA_ERR_LOCK_DEADLOCK; | |
| 3821 | } | ||
| 3822 | |||
| 3823 | // Set status for the need to update generated fields | ||
| 3824 | 5417 | m_update_generated_read_fields = table->has_gcol(); | |
| 3825 | |||
| 3826 |
13/27✓ Branch 0 taken 5409 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 3493 times.
✓ Branch 3 taken 1916 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3493 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3493 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3493 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3493 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1916 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1916 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1902 times.
✓ Branch 18 taken 14 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 8 times.
✗ Branch 26 not taken.
|
5417 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, |
| 3827 | { result = index_last(buf); }) | ||
| 3828 |
4/4✓ Branch 0 taken 5296 times.
✓ Branch 1 taken 121 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 5272 times.
|
5417 | if (!result && m_update_generated_read_fields) { |
| 3829 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | result = update_generated_read_fields(buf, table, active_index); |
| 3830 | 24 | m_update_generated_read_fields = false; | |
| 3831 | } | ||
| 3832 | 5417 | table->set_row_status_from_handler(result); | |
| 3833 | |||
| 3834 |
2/2✓ Branch 0 taken 5296 times.
✓ Branch 1 taken 121 times.
|
5417 | if (likely(!result)) { |
| 3835 | 5296 | update_index_stats(active_index); | |
| 3836 | } | ||
| 3837 | |||
| 3838 | 5417 | return result; | |
| 3839 | 5417 | } | |
| 3840 | |||
| 3841 | /** | ||
| 3842 | Reads the next same row via index. | ||
| 3843 | |||
| 3844 | @param[out] buf Row data | ||
| 3845 | @param key Key to search for | ||
| 3846 | @param keylen Length of key | ||
| 3847 | |||
| 3848 | @return Operation status. | ||
| 3849 | @retval 0 Success | ||
| 3850 | @retval HA_ERR_END_OF_FILE Row not found | ||
| 3851 | @retval != 0 Error | ||
| 3852 | */ | ||
| 3853 | |||
| 3854 | 102627778 | int handler::ha_index_next_same(uchar *buf, const uchar *key, uint keylen) { | |
| 3855 | int result; | ||
| 3856 |
1/2✓ Branch 0 taken 102627807 times.
✗ Branch 1 not taken.
|
102627778 | DBUG_TRACE; |
| 3857 |
3/4✓ Branch 0 taken 102557737 times.
✓ Branch 1 taken 70070 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 102557737 times.
|
102627807 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 3858 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102627807 times.
|
102627807 | assert(inited == INDEX); |
| 3859 |
3/4✓ Branch 0 taken 1106974 times.
✓ Branch 1 taken 101520833 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1106974 times.
|
102627807 | assert(!pushed_idx_cond || buf == table->record[0]); |
| 3860 | |||
| 3861 | // Set status for the need to update generated fields | ||
| 3862 | 102627807 | m_update_generated_read_fields = table->has_gcol(); | |
| 3863 |
14/27✓ Branch 0 taken 3612952 times.
✓ Branch 1 taken 99014858 times.
✓ Branch 2 taken 585902 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3027050 times.
✓ Branch 5 taken 585902 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 585902 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 585901 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 585901 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 3027050 times.
✓ Branch 21 taken 3027050 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1942391 times.
✓ Branch 24 taken 1084659 times.
✓ Branch 25 taken 99014820 times.
✗ Branch 26 not taken.
|
102627810 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, |
| 3864 | { result = index_next_same(buf, key, keylen); }) | ||
| 3865 |
4/4✓ Branch 0 taken 84660607 times.
✓ Branch 1 taken 17967165 times.
✓ Branch 2 taken 1278 times.
✓ Branch 3 taken 84659329 times.
|
102627772 | if (!result && m_update_generated_read_fields) { |
| 3866 |
1/2✓ Branch 0 taken 1278 times.
✗ Branch 1 not taken.
|
1278 | result = update_generated_read_fields(buf, table, active_index); |
| 3867 | 1278 | m_update_generated_read_fields = false; | |
| 3868 | } | ||
| 3869 | // Filter duplicate records from multi-value index read. | ||
| 3870 | // (m_unique != nullptr in case of multi-value index read) | ||
| 3871 | // In case of range scan, duplicate records are filtered in | ||
| 3872 | // multi_range_read_next() | ||
| 3873 | |||
| 3874 |
8/8✓ Branch 0 taken 84660615 times.
✓ Branch 1 taken 17967157 times.
✓ Branch 2 taken 84253108 times.
✓ Branch 3 taken 407507 times.
✓ Branch 4 taken 130 times.
✓ Branch 5 taken 84252978 times.
✓ Branch 6 taken 44 times.
✓ Branch 7 taken 102627728 times.
|
102627902 | if (!result && !mrr_have_range && m_unique != nullptr && |
| 3875 |
3/4✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 86 times.
|
130 | filter_dup_records()) { |
| 3876 | 44 | result = HA_ERR_KEY_NOT_FOUND; | |
| 3877 | } | ||
| 3878 | |||
| 3879 | 102627772 | table->set_row_status_from_handler(result); | |
| 3880 | |||
| 3881 |
2/2✓ Branch 0 taken 84660570 times.
✓ Branch 1 taken 17967223 times.
|
102627796 | if (likely(!result)) { |
| 3882 | 84660570 | update_index_stats(active_index); | |
| 3883 | } | ||
| 3884 | |||
| 3885 | 102627801 | return result; | |
| 3886 | 102627794 | } | |
| 3887 | |||
| 3888 | /** | ||
| 3889 | Read first row (only) from a table. | ||
| 3890 | |||
| 3891 | This is never called for tables whose storage engine do not contain exact | ||
| 3892 | statistics on number of records, e.g. InnoDB. | ||
| 3893 | |||
| 3894 | @note Since there is only one implementation for this function, it is | ||
| 3895 | non-virtual and does not call a protected inner function, like | ||
| 3896 | most other handler functions. | ||
| 3897 | |||
| 3898 | @note Implementation only calls other handler functions, so there is no need | ||
| 3899 | to update generated columns nor set table status. | ||
| 3900 | */ | ||
| 3901 | ✗ | int handler::ha_read_first_row(uchar *buf, uint primary_key) { | |
| 3902 | int error; | ||
| 3903 | ✗ | DBUG_TRACE; | |
| 3904 | |||
| 3905 | ✗ | ha_statistic_increment(&System_status_var::ha_read_first_count); | |
| 3906 | |||
| 3907 | /* | ||
| 3908 | If there is very few deleted rows in the table, find the first row by | ||
| 3909 | scanning the table. | ||
| 3910 | TODO remove the test for HA_READ_ORDER | ||
| 3911 | */ | ||
| 3912 | ✗ | if (stats.deleted < 10 || primary_key >= MAX_KEY || | |
| 3913 | ✗ | !(index_flags(primary_key, 0, false) & HA_READ_ORDER)) { | |
| 3914 | ✗ | if (!(error = ha_rnd_init(true))) { | |
| 3915 | ✗ | while ((error = ha_rnd_next(buf)) == HA_ERR_RECORD_DELETED) | |
| 3916 | /* skip deleted row */; | ||
| 3917 | ✗ | const int end_error = ha_rnd_end(); | |
| 3918 | ✗ | if (!error) error = end_error; | |
| 3919 | } | ||
| 3920 | } else { | ||
| 3921 | /* Find the first row through the primary key */ | ||
| 3922 | ✗ | if (!(error = ha_index_init(primary_key, false))) { | |
| 3923 | ✗ | error = ha_index_first(buf); | |
| 3924 | ✗ | const int end_error = ha_index_end(); | |
| 3925 | ✗ | if (!error) error = end_error; | |
| 3926 | } | ||
| 3927 | } | ||
| 3928 | ✗ | return error; | |
| 3929 | } | ||
| 3930 | |||
| 3931 | ✗ | int handler::ha_index_read_pushed(uchar *buf, const uchar *key, | |
| 3932 | key_part_map keypart_map) { | ||
| 3933 | ✗ | DBUG_TRACE; | |
| 3934 | |||
| 3935 | // Set status for the need to update generated fields | ||
| 3936 | ✗ | m_update_generated_read_fields = table->has_gcol(); | |
| 3937 | |||
| 3938 | ✗ | int result = index_read_pushed(buf, key, keypart_map); | |
| 3939 | ✗ | if (!result && m_update_generated_read_fields) { | |
| 3940 | ✗ | result = update_generated_read_fields(buf, table, active_index); | |
| 3941 | ✗ | m_update_generated_read_fields = false; | |
| 3942 | } | ||
| 3943 | ✗ | table->set_row_status_from_handler(result); | |
| 3944 | ✗ | return result; | |
| 3945 | } | ||
| 3946 | |||
| 3947 | ✗ | int handler::ha_index_next_pushed(uchar *buf) { | |
| 3948 | ✗ | DBUG_TRACE; | |
| 3949 | |||
| 3950 | // Set status for the need to update generated fields | ||
| 3951 | ✗ | m_update_generated_read_fields = table->has_gcol(); | |
| 3952 | |||
| 3953 | ✗ | int result = index_next_pushed(buf); | |
| 3954 | ✗ | if (!result && m_update_generated_read_fields) { | |
| 3955 | ✗ | result = update_generated_read_fields(buf, table, active_index); | |
| 3956 | ✗ | m_update_generated_read_fields = false; | |
| 3957 | } | ||
| 3958 | ✗ | table->set_row_status_from_handler(result); | |
| 3959 | ✗ | return result; | |
| 3960 | } | ||
| 3961 | |||
| 3962 | /** | ||
| 3963 | Generate the next auto-increment number based on increment and offset. | ||
| 3964 | computes the lowest number | ||
| 3965 | - strictly greater than "nr" | ||
| 3966 | - of the form: auto_increment_offset + N * auto_increment_increment | ||
| 3967 | If overflow happened then return MAX_ULONGLONG value as an | ||
| 3968 | indication of overflow. | ||
| 3969 | In most cases increment= offset= 1, in which case we get: | ||
| 3970 | @verbatim 1,2,3,4,5,... @endverbatim | ||
| 3971 | If increment=10 and offset=5 and previous number is 1, we get: | ||
| 3972 | @verbatim 1,5,15,25,35,... @endverbatim | ||
| 3973 | */ | ||
| 3974 | 20752443 | inline ulonglong compute_next_insert_id(ulonglong nr, | |
| 3975 | struct System_variables *variables) { | ||
| 3976 | 20752443 | const ulonglong save_nr = nr; | |
| 3977 | |||
| 3978 |
2/2✓ Branch 0 taken 20308316 times.
✓ Branch 1 taken 444127 times.
|
20752443 | if (variables->auto_increment_increment == 1) |
| 3979 | 20308316 | nr = nr + 1; // optimization of the formula below | |
| 3980 | else { | ||
| 3981 | 444127 | nr = (((nr + variables->auto_increment_increment - | |
| 3982 | 444127 | variables->auto_increment_offset)) / | |
| 3983 | 444127 | (ulonglong)variables->auto_increment_increment); | |
| 3984 | 444127 | nr = (nr * (ulonglong)variables->auto_increment_increment + | |
| 3985 | 444127 | variables->auto_increment_offset); | |
| 3986 | } | ||
| 3987 | |||
| 3988 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 20752446 times.
|
20752443 | if (unlikely(nr <= save_nr)) return ULLONG_MAX; |
| 3989 | |||
| 3990 | 20752446 | return nr; | |
| 3991 | } | ||
| 3992 | |||
| 3993 | 1736611 | void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr) { | |
| 3994 | /* | ||
| 3995 | If we have set THD::next_insert_id previously and plan to insert an | ||
| 3996 | explicitely-specified value larger than this, we need to increase | ||
| 3997 | THD::next_insert_id to be greater than the explicit value. | ||
| 3998 | */ | ||
| 3999 |
4/4✓ Branch 0 taken 331 times.
✓ Branch 1 taken 1736280 times.
✓ Branch 2 taken 266 times.
✓ Branch 3 taken 65 times.
|
1736611 | if ((next_insert_id > 0) && (nr >= next_insert_id)) |
| 4000 | 266 | set_next_insert_id(compute_next_insert_id(nr, &table->in_use->variables)); | |
| 4001 | 1736611 | } | |
| 4002 | |||
| 4003 | /** @brief | ||
| 4004 | Computes the largest number X: | ||
| 4005 | - smaller than or equal to "nr" | ||
| 4006 | - of the form: auto_increment_offset + N * auto_increment_increment | ||
| 4007 | where N>=0. | ||
| 4008 | |||
| 4009 | SYNOPSIS | ||
| 4010 | prev_insert_id | ||
| 4011 | nr Number to "round down" | ||
| 4012 | variables variables struct containing auto_increment_increment and | ||
| 4013 | auto_increment_offset | ||
| 4014 | |||
| 4015 | RETURN | ||
| 4016 | The number X if it exists, "nr" otherwise. | ||
| 4017 | */ | ||
| 4018 | 19 | inline ulonglong prev_insert_id(ulonglong nr, | |
| 4019 | struct System_variables *variables) { | ||
| 4020 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 13 times.
|
19 | if (unlikely(nr < variables->auto_increment_offset)) { |
| 4021 | /* | ||
| 4022 | There's nothing good we can do here. That is a pathological case, where | ||
| 4023 | the offset is larger than the column's max possible value, i.e. not even | ||
| 4024 | the first sequence value may be inserted. User will receive warning. | ||
| 4025 | */ | ||
| 4026 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | DBUG_PRINT("info", ("auto_increment: nr: %lu cannot honour " |
| 4027 | "auto_increment_offset: %lu", | ||
| 4028 | (ulong)nr, variables->auto_increment_offset)); | ||
| 4029 | 6 | return nr; | |
| 4030 | } | ||
| 4031 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
|
13 | if (variables->auto_increment_increment == 1) |
| 4032 | 7 | return nr; // optimization of the formula below | |
| 4033 | 6 | nr = (((nr - variables->auto_increment_offset)) / | |
| 4034 | 6 | (ulonglong)variables->auto_increment_increment); | |
| 4035 | 6 | return (nr * (ulonglong)variables->auto_increment_increment + | |
| 4036 | 6 | variables->auto_increment_offset); | |
| 4037 | } | ||
| 4038 | |||
| 4039 | /** | ||
| 4040 | Update the auto_increment field if necessary. | ||
| 4041 | |||
| 4042 | Updates columns with type NEXT_NUMBER if: | ||
| 4043 | |||
| 4044 | - If column value is set to NULL (in which case | ||
| 4045 | autoinc_field_has_explicit_non_null_value is 0) | ||
| 4046 | - If column is set to 0 and (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) is not | ||
| 4047 | set. In the future we will only set NEXT_NUMBER fields if one sets them | ||
| 4048 | to NULL (or they are not included in the insert list). | ||
| 4049 | |||
| 4050 | In those cases, we check if the currently reserved interval still has | ||
| 4051 | values we have not used. If yes, we pick the smallest one and use it. | ||
| 4052 | Otherwise: | ||
| 4053 | |||
| 4054 | - If a list of intervals has been provided to the statement via SET | ||
| 4055 | INSERT_ID or via an Intvar_log_event (in a replication slave), we pick the | ||
| 4056 | first unused interval from this list, consider it as reserved. | ||
| 4057 | |||
| 4058 | - Otherwise we set the column for the first row to the value | ||
| 4059 | next_insert_id(get_auto_increment(column))) which is usually | ||
| 4060 | max-used-column-value+1. | ||
| 4061 | We call get_auto_increment() for the first row in a multi-row | ||
| 4062 | statement. get_auto_increment() will tell us the interval of values it | ||
| 4063 | reserved for us. | ||
| 4064 | |||
| 4065 | - In both cases, for the following rows we use those reserved values without | ||
| 4066 | calling the handler again (we just progress in the interval, computing | ||
| 4067 | each new value from the previous one). Until we have exhausted them, then | ||
| 4068 | we either take the next provided interval or call get_auto_increment() | ||
| 4069 | again to reserve a new interval. | ||
| 4070 | |||
| 4071 | - In both cases, the reserved intervals are remembered in | ||
| 4072 | thd->auto_inc_intervals_in_cur_stmt_for_binlog if statement-based | ||
| 4073 | binlogging; the last reserved interval is remembered in | ||
| 4074 | auto_inc_interval_for_cur_row. The number of reserved intervals is | ||
| 4075 | remembered in auto_inc_intervals_count. It differs from the number of | ||
| 4076 | elements in thd->auto_inc_intervals_in_cur_stmt_for_binlog() because the | ||
| 4077 | latter list is cumulative over all statements forming one binlog event | ||
| 4078 | (when stored functions and triggers are used), and collapses two | ||
| 4079 | contiguous intervals in one (see its append() method). | ||
| 4080 | |||
| 4081 | The idea is that generated auto_increment values are predictable and | ||
| 4082 | independent of the column values in the table. This is needed to be | ||
| 4083 | able to replicate into a table that already has rows with a higher | ||
| 4084 | auto-increment value than the one that is inserted. | ||
| 4085 | |||
| 4086 | After we have already generated an auto-increment number and the user | ||
| 4087 | inserts a column with a higher value than the last used one, we will | ||
| 4088 | start counting from the inserted value. | ||
| 4089 | |||
| 4090 | This function's "outputs" are: the table's auto_increment field is filled | ||
| 4091 | with a value, thd->next_insert_id is filled with the value to use for the | ||
| 4092 | next row, if a value was autogenerated for the current row it is stored in | ||
| 4093 | thd->insert_id_for_cur_row, if get_auto_increment() was called | ||
| 4094 | thd->auto_inc_interval_for_cur_row is modified, if that interval is not | ||
| 4095 | present in thd->auto_inc_intervals_in_cur_stmt_for_binlog it is added to | ||
| 4096 | this list. | ||
| 4097 | |||
| 4098 | @todo | ||
| 4099 | Replace all references to "next number" or NEXT_NUMBER to | ||
| 4100 | "auto_increment", everywhere (see below: there is | ||
| 4101 | table->autoinc_field_has_explicit_non_null_value, and there also exists | ||
| 4102 | table->next_number_field, it's not consistent). | ||
| 4103 | |||
| 4104 | @retval | ||
| 4105 | 0 ok | ||
| 4106 | @retval | ||
| 4107 | HA_ERR_AUTOINC_READ_FAILED get_auto_increment() was called and | ||
| 4108 | returned ~(ulonglong) 0 | ||
| 4109 | @retval | ||
| 4110 | HA_ERR_AUTOINC_ERANGE storing value in field caused strict mode | ||
| 4111 | failure. | ||
| 4112 | */ | ||
| 4113 | |||
| 4114 | #define AUTO_INC_DEFAULT_NB_ROWS 1 // Some prefer 1024 here | ||
| 4115 | #define AUTO_INC_DEFAULT_NB_MAX_BITS 16 | ||
| 4116 | #define AUTO_INC_DEFAULT_NB_MAX ((1 << AUTO_INC_DEFAULT_NB_MAX_BITS) - 1) | ||
| 4117 | |||
| 4118 | 15413932 | int handler::update_auto_increment() { | |
| 4119 | 15413932 | ulonglong nr, nb_reserved_values = 0; | |
| 4120 | 15413932 | bool append = false; | |
| 4121 | 15413932 | THD *thd = table->in_use; | |
| 4122 | 15413932 | struct System_variables *variables = &thd->variables; | |
| 4123 |
3/4✓ Branch 0 taken 13612888 times.
✓ Branch 1 taken 1801044 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13612888 times.
|
15413932 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 4124 |
1/2✓ Branch 0 taken 15414223 times.
✗ Branch 1 not taken.
|
15413932 | DBUG_TRACE; |
| 4125 | |||
| 4126 | /* | ||
| 4127 | next_insert_id is a "cursor" into the reserved interval, it may go greater | ||
| 4128 | than the interval, but not smaller. | ||
| 4129 | */ | ||
| 4130 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15414169 times.
|
15414223 | assert(next_insert_id >= auto_inc_interval_for_cur_row.minimum()); |
| 4131 | |||
| 4132 |
5/6✓ Branch 0 taken 15414240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13677337 times.
✓ Branch 3 taken 1736903 times.
✓ Branch 4 taken 1736938 times.
✓ Branch 5 taken 13677302 times.
|
29091506 | if ((nr = table->next_number_field->val_int()) != 0 || |
| 4133 |
2/2✓ Branch 0 taken 6549342 times.
✓ Branch 1 taken 7127995 times.
|
13677337 | (table->autoinc_field_has_explicit_non_null_value && |
| 4134 |
2/2✓ Branch 0 taken 87 times.
✓ Branch 1 taken 6549255 times.
|
6549342 | thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)) { |
| 4135 | /* | ||
| 4136 | First test if the query was aborted due to strict mode constraints. | ||
| 4137 | */ | ||
| 4138 |
7/8✓ Branch 0 taken 1736981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1736979 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1736984 times.
|
1736945 | if (thd->is_error() && |
| 4139 | 2 | thd->get_stmt_da()->mysql_errno() == ER_TRUNCATED_WRONG_VALUE) | |
| 4140 | 2 | return HA_ERR_AUTOINC_ERANGE; | |
| 4141 | |||
| 4142 | /* | ||
| 4143 | Update next_insert_id if we had already generated a value in this | ||
| 4144 | statement (case of INSERT VALUES(null),(3763),(null): | ||
| 4145 | the last NULL needs to insert 3764, not the value of the first NULL plus | ||
| 4146 | 1). | ||
| 4147 | Also we should take into account the the sign of the value. | ||
| 4148 | Since auto_increment value can't have negative value we should update | ||
| 4149 | next_insert_id only in case when we INSERTing explicit positive value. | ||
| 4150 | It means that for a table that has SIGNED INTEGER column when we execute | ||
| 4151 | the following statement | ||
| 4152 | INSERT INTO t1 VALUES( NULL), (-1), (NULL) | ||
| 4153 | we shouldn't call adjust_next_insert_id_after_explicit_value() | ||
| 4154 | and the result row will be (1, -1, 2) (for new opened connection | ||
| 4155 | to the server). On the other hand, for the statement | ||
| 4156 | INSERT INTO t1 VALUES( NULL), (333), (NULL) | ||
| 4157 | we should call adjust_next_insert_id_after_explicit_value() | ||
| 4158 | and result row will be (1, 333, 334). | ||
| 4159 | */ | ||
| 4160 |
7/8✓ Branch 0 taken 1736893 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1355913 times.
✓ Branch 3 taken 380980 times.
✓ Branch 4 taken 1355701 times.
✓ Branch 5 taken 212 times.
✓ Branch 6 taken 1736721 times.
✓ Branch 7 taken 172 times.
|
1736984 | if (table->next_number_field->is_unsigned() || ((longlong)nr) > 0) |
| 4161 |
1/2✓ Branch 0 taken 1736662 times.
✗ Branch 1 not taken.
|
1736721 | adjust_next_insert_id_after_explicit_value(nr); |
| 4162 | |||
| 4163 | 1736834 | insert_id_for_cur_row = 0; // didn't generate anything | |
| 4164 | 1736834 | return 0; | |
| 4165 | } | ||
| 4166 | |||
| 4167 |
3/4✓ Branch 0 taken 13677217 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 13677213 times.
|
13677302 | if (next_insert_id > table->next_number_field->get_max_int_value()) |
| 4168 | 4 | return HA_ERR_AUTOINC_READ_FAILED; | |
| 4169 | |||
| 4170 |
2/2✓ Branch 0 taken 7113025 times.
✓ Branch 1 taken 6564256 times.
|
13677213 | if ((nr = next_insert_id) >= auto_inc_interval_for_cur_row.maximum()) { |
| 4171 | /* next_insert_id is beyond what is reserved, so we reserve more. */ | ||
| 4172 | 7113025 | const Discrete_interval *forced = thd->auto_inc_intervals_forced.get_next(); | |
| 4173 |
2/2✓ Branch 0 taken 37953 times.
✓ Branch 1 taken 7075066 times.
|
7113019 | if (forced != nullptr) { |
| 4174 | 37953 | nr = forced->minimum(); | |
| 4175 | /* | ||
| 4176 | In a multi insert statement when the number of affected rows is known | ||
| 4177 | then reserve those many number of auto increment values. So that | ||
| 4178 | interval will be starting value to starting value + number of affected | ||
| 4179 | rows * increment of auto increment. | ||
| 4180 | */ | ||
| 4181 | 37959 | nb_reserved_values = (estimation_rows_to_insert > 0) | |
| 4182 |
2/2✓ Branch 0 taken 37768 times.
✓ Branch 1 taken 191 times.
|
37959 | ? estimation_rows_to_insert |
| 4183 | 191 | : forced->values(); | |
| 4184 | } else { | ||
| 4185 | /* | ||
| 4186 | handler::estimation_rows_to_insert was set by | ||
| 4187 | handler::ha_start_bulk_insert(); if 0 it means "unknown". | ||
| 4188 | */ | ||
| 4189 | ulonglong nb_desired_values; | ||
| 4190 | /* | ||
| 4191 | If an estimation was given to the engine: | ||
| 4192 | - use it. | ||
| 4193 | - if we already reserved numbers, it means the estimation was | ||
| 4194 | not accurate, then we'll reserve 2*AUTO_INC_DEFAULT_NB_ROWS the 2nd | ||
| 4195 | time, twice that the 3rd time etc. | ||
| 4196 | If no estimation was given, use those increasing defaults from the | ||
| 4197 | start, starting from AUTO_INC_DEFAULT_NB_ROWS. | ||
| 4198 | Don't go beyond a max to not reserve "way too much" (because | ||
| 4199 | reservation means potentially losing unused values). | ||
| 4200 | Note that in prelocked mode no estimation is given. | ||
| 4201 | */ | ||
| 4202 | |||
| 4203 |
4/4✓ Branch 0 taken 7040701 times.
✓ Branch 1 taken 34365 times.
✓ Branch 2 taken 514077 times.
✓ Branch 3 taken 6526624 times.
|
7075066 | if ((auto_inc_intervals_count == 0) && (estimation_rows_to_insert > 0)) |
| 4204 | 514077 | nb_desired_values = estimation_rows_to_insert; | |
| 4205 |
2/2✓ Branch 0 taken 6526621 times.
✓ Branch 1 taken 34368 times.
|
6560989 | else if ((auto_inc_intervals_count == 0) && |
| 4206 |
2/2✓ Branch 0 taken 3263 times.
✓ Branch 1 taken 6523358 times.
|
6526621 | (thd->lex->bulk_insert_row_cnt > 0)) { |
| 4207 | /* | ||
| 4208 | For multi-row inserts, if the bulk inserts cannot be started, the | ||
| 4209 | handler::estimation_rows_to_insert will not be set. But we still | ||
| 4210 | want to reserve the autoinc values. | ||
| 4211 | */ | ||
| 4212 | 3263 | nb_desired_values = thd->lex->bulk_insert_row_cnt; | |
| 4213 | } else /* go with the increasing defaults */ | ||
| 4214 | { | ||
| 4215 | /* avoid overflow in formula, with this if() */ | ||
| 4216 |
2/2✓ Branch 0 taken 6557688 times.
✓ Branch 1 taken 38 times.
|
6557726 | if (auto_inc_intervals_count <= AUTO_INC_DEFAULT_NB_MAX_BITS) { |
| 4217 | 6557688 | nb_desired_values = | |
| 4218 | 6557688 | AUTO_INC_DEFAULT_NB_ROWS * (1 << auto_inc_intervals_count); | |
| 4219 | 6557687 | nb_desired_values = | |
| 4220 | 6557688 | std::min(nb_desired_values, ulonglong(AUTO_INC_DEFAULT_NB_MAX)); | |
| 4221 | } else | ||
| 4222 | 38 | nb_desired_values = AUTO_INC_DEFAULT_NB_MAX; | |
| 4223 | } | ||
| 4224 | /* This call ignores all its parameters but nr, currently */ | ||
| 4225 | 7075065 | get_auto_increment(variables->auto_increment_offset, | |
| 4226 |
1/2✓ Branch 0 taken 7075080 times.
✗ Branch 1 not taken.
|
7075065 | variables->auto_increment_increment, nb_desired_values, |
| 4227 | &nr, &nb_reserved_values); | ||
| 4228 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7075066 times.
|
7075080 | if (nr == ULLONG_MAX) return HA_ERR_AUTOINC_READ_FAILED; // Mark failure |
| 4229 | |||
| 4230 | /* | ||
| 4231 | That rounding below should not be needed when all engines actually | ||
| 4232 | respect offset and increment in get_auto_increment(). But they don't | ||
| 4233 | so we still do it. Wonder if for the not-first-in-index we should do | ||
| 4234 | it. Hope that this rounding didn't push us out of the interval; even | ||
| 4235 | if it did we cannot do anything about it (calling the engine again | ||
| 4236 | will not help as we inserted no row). | ||
| 4237 | */ | ||
| 4238 | 7075066 | nr = compute_next_insert_id(nr - 1, variables); | |
| 4239 | } | ||
| 4240 | |||
| 4241 |
2/2✓ Branch 0 taken 7112915 times.
✓ Branch 1 taken 34 times.
|
7112949 | if (table->s->next_number_keypart == 0) { |
| 4242 | /* We must defer the appending until "nr" has been possibly truncated */ | ||
| 4243 | 7112915 | append = true; | |
| 4244 | } else { | ||
| 4245 | /* | ||
| 4246 | For such auto_increment there is no notion of interval, just a | ||
| 4247 | singleton. The interval is not even stored in | ||
| 4248 | thd->auto_inc_interval_for_cur_row, so we are sure to call the engine | ||
| 4249 | for next row. | ||
| 4250 | */ | ||
| 4251 |
3/8✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
34 | DBUG_PRINT("info", ("auto_increment: special not-first-in-index")); |
| 4252 | } | ||
| 4253 | } | ||
| 4254 | |||
| 4255 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 13677268 times.
|
13677213 | if (unlikely(nr == ULLONG_MAX)) return HA_ERR_AUTOINC_ERANGE; |
| 4256 | |||
| 4257 |
5/8✓ Branch 0 taken 13677275 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13677292 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 415 times.
✓ Branch 5 taken 13676877 times.
✓ Branch 6 taken 415 times.
✗ Branch 7 not taken.
|
13677268 | DBUG_PRINT("info", ("auto_increment: %lu", (ulong)nr)); |
| 4258 | |||
| 4259 |
3/4✓ Branch 0 taken 13677256 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 13677199 times.
|
13677292 | if (unlikely(table->next_number_field->store((longlong)nr, true))) { |
| 4260 | /* | ||
| 4261 | first test if the query was aborted due to strict mode constraints | ||
| 4262 | */ | ||
| 4263 |
6/8✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19 times.
✓ Branch 7 taken 19 times.
|
57 | if (thd->is_error() && |
| 4264 | 19 | thd->get_stmt_da()->mysql_errno() == ER_WARN_DATA_OUT_OF_RANGE) | |
| 4265 | 19 | return HA_ERR_AUTOINC_ERANGE; | |
| 4266 | |||
| 4267 | /* | ||
| 4268 | field refused this value (overflow) and truncated it, use the result of | ||
| 4269 | the truncation (which is going to be inserted); however we try to | ||
| 4270 | decrease it to honour auto_increment_* variables. | ||
| 4271 | That will shift the left bound of the reserved interval, we don't | ||
| 4272 | bother shifting the right bound (anyway any other value from this | ||
| 4273 | interval will cause a duplicate key). | ||
| 4274 | */ | ||
| 4275 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
|
19 | nr = prev_insert_id(table->next_number_field->val_int(), variables); |
| 4276 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
|
19 | if (unlikely(table->next_number_field->store((longlong)nr, true))) |
| 4277 | ✗ | nr = table->next_number_field->val_int(); | |
| 4278 | } | ||
| 4279 |
2/2✓ Branch 0 taken 7112855 times.
✓ Branch 1 taken 6564363 times.
|
13677218 | if (append) { |
| 4280 | 7112855 | auto_inc_interval_for_cur_row.replace(nr, nb_reserved_values, | |
| 4281 | 7112855 | variables->auto_increment_increment); | |
| 4282 | 7112889 | auto_inc_intervals_count++; | |
| 4283 | /* Row-based replication does not need to store intervals in binlog */ | ||
| 4284 | #ifdef WITH_WSREP | ||
| 4285 |
15/16✓ Branch 0 taken 7112893 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3924357 times.
✓ Branch 3 taken 3188536 times.
✓ Branch 4 taken 141005 times.
✓ Branch 5 taken 3783352 times.
✓ Branch 6 taken 76692 times.
✓ Branch 7 taken 64313 times.
✓ Branch 8 taken 76261 times.
✓ Branch 9 taken 431 times.
✓ Branch 10 taken 2307360 times.
✓ Branch 11 taken 4805119 times.
✓ Branch 12 taken 1800805 times.
✓ Branch 13 taken 506997 times.
✓ Branch 14 taken 1800805 times.
✓ Branch 15 taken 5312116 times.
|
9420691 | if (((WSREP_EMULATE_BINLOG(thd)) || mysql_bin_log.is_open()) && |
| 4286 | 2307791 | !thd->is_current_stmt_binlog_format_row()) | |
| 4287 | #else | ||
| 4288 | if (mysql_bin_log.is_open() && !thd->is_current_stmt_binlog_format_row()) | ||
| 4289 | #endif /* WITH_WSREP */ | ||
| 4290 |
1/2✓ Branch 0 taken 1800805 times.
✗ Branch 1 not taken.
|
1800804 | thd->auto_inc_intervals_in_cur_stmt_for_binlog.append( |
| 4291 | auto_inc_interval_for_cur_row.minimum(), | ||
| 4292 | auto_inc_interval_for_cur_row.values(), | ||
| 4293 | 1800805 | variables->auto_increment_increment); | |
| 4294 | } | ||
| 4295 | |||
| 4296 | /* | ||
| 4297 | Record this autogenerated value. If the caller then | ||
| 4298 | succeeds to insert this value, it will call | ||
| 4299 | record_first_successful_insert_id_in_cur_stmt() | ||
| 4300 | which will set first_successful_insert_id_in_cur_stmt if it's not | ||
| 4301 | already set. | ||
| 4302 | */ | ||
| 4303 | 13677284 | insert_id_for_cur_row = nr; | |
| 4304 | /* | ||
| 4305 | Set next insert id to point to next auto-increment value to be able to | ||
| 4306 | handle multi-row statements. | ||
| 4307 | */ | ||
| 4308 |
1/2✓ Branch 0 taken 13677277 times.
✗ Branch 1 not taken.
|
13677284 | set_next_insert_id(compute_next_insert_id(nr, variables)); |
| 4309 | |||
| 4310 | 13677277 | return 0; | |
| 4311 | 15414154 | } | |
| 4312 | |||
| 4313 | /** @brief | ||
| 4314 | MySQL signal that it changed the column bitmap | ||
| 4315 | |||
| 4316 | USAGE | ||
| 4317 | This is for handlers that needs to setup their own column bitmaps. | ||
| 4318 | Normally the handler should set up their own column bitmaps in | ||
| 4319 | index_init() or rnd_init() and in any column_bitmaps_signal() call after | ||
| 4320 | this. | ||
| 4321 | |||
| 4322 | The handler is allowed to do changes to the bitmap after an index_init or | ||
| 4323 | rnd_init() call is made as after this, MySQL will not use the bitmap | ||
| 4324 | for any program logic checking. | ||
| 4325 | */ | ||
| 4326 | 223299924 | void handler::column_bitmaps_signal() { | |
| 4327 |
1/2✓ Branch 0 taken 223302041 times.
✗ Branch 1 not taken.
|
223299924 | DBUG_TRACE; |
| 4328 |
5/8✓ Branch 0 taken 223301868 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 223301911 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12808 times.
✓ Branch 5 taken 223289103 times.
✓ Branch 6 taken 12808 times.
✗ Branch 7 not taken.
|
223302041 | DBUG_PRINT("info", ("read_set: %p write_set: %p", table->read_set, |
| 4329 | table->write_set)); | ||
| 4330 | 223301911 | } | |
| 4331 | |||
| 4332 | /** | ||
| 4333 | Reserves an interval of auto_increment values from the handler. | ||
| 4334 | |||
| 4335 | @param offset offset (modulus increment) | ||
| 4336 | @param increment increment between calls | ||
| 4337 | @param nb_desired_values how many values we want | ||
| 4338 | @param[out] first_value the first value reserved by the handler | ||
| 4339 | @param[out] nb_reserved_values how many values the handler reserved | ||
| 4340 | |||
| 4341 | offset and increment means that we want values to be of the form | ||
| 4342 | offset + N * increment, where N>=0 is integer. | ||
| 4343 | If the function sets *first_value to ULLONG_MAX it means an error. | ||
| 4344 | If the function sets *nb_reserved_values to ULLONG_MAX it means it has | ||
| 4345 | reserved to "positive infinite". | ||
| 4346 | */ | ||
| 4347 | |||
| 4348 | 3 | void handler::get_auto_increment(ulonglong offset [[maybe_unused]], | |
| 4349 | ulonglong increment [[maybe_unused]], | ||
| 4350 | ulonglong nb_desired_values [[maybe_unused]], | ||
| 4351 | ulonglong *first_value, | ||
| 4352 | ulonglong *nb_reserved_values) { | ||
| 4353 | ulonglong nr; | ||
| 4354 | int error; | ||
| 4355 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | DBUG_TRACE; |
| 4356 | |||
| 4357 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | (void)extra(HA_EXTRA_KEYREAD); |
| 4358 | 3 | table->mark_columns_used_by_index_no_reset(table->s->next_number_index, | |
| 4359 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | table->read_set); |
| 4360 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | column_bitmaps_signal(); |
| 4361 | |||
| 4362 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
3 | if (ha_index_init(table->s->next_number_index, true)) { |
| 4363 | /* This should never happen, assert in debug, and fail in release build */ | ||
| 4364 | ✗ | assert(0); | |
| 4365 | *first_value = ULLONG_MAX; | ||
| 4366 | return; | ||
| 4367 | } | ||
| 4368 | |||
| 4369 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (table->s->next_number_keypart == 0) { // Autoincrement at key-start |
| 4370 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | error = ha_index_last(table->record[1]); |
| 4371 | /* | ||
| 4372 | MySQL implicitly assumes such method does locking (as MySQL decides to | ||
| 4373 | use nr+increment without checking again with the handler, in | ||
| 4374 | handler::update_auto_increment()), so reserves to infinite. | ||
| 4375 | */ | ||
| 4376 | 3 | *nb_reserved_values = ULLONG_MAX; | |
| 4377 | } else { | ||
| 4378 | uchar key[MAX_KEY_LENGTH]; | ||
| 4379 | ✗ | key_copy(key, table->record[0], | |
| 4380 | ✗ | table->key_info + table->s->next_number_index, | |
| 4381 | ✗ | table->s->next_number_key_offset); | |
| 4382 | error = | ||
| 4383 | ✗ | ha_index_read_map(table->record[1], key, | |
| 4384 | ✗ | make_prev_keypart_map(table->s->next_number_keypart), | |
| 4385 | HA_READ_PREFIX_LAST); | ||
| 4386 | /* | ||
| 4387 | MySQL needs to call us for next row: assume we are inserting ("a",null) | ||
| 4388 | here, we return 3, and next this statement will want to insert | ||
| 4389 | ("b",null): there is no reason why ("b",3+1) would be the good row to | ||
| 4390 | insert: maybe it already exists, maybe 3+1 is too large... | ||
| 4391 | */ | ||
| 4392 | ✗ | *nb_reserved_values = 1; | |
| 4393 | } | ||
| 4394 | |||
| 4395 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (error) { |
| 4396 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3 | if (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND) { |
| 4397 | /* No entry found, start with 1. */ | ||
| 4398 | 3 | nr = 1; | |
| 4399 | } else { | ||
| 4400 | ✗ | assert(0); | |
| 4401 | nr = ULLONG_MAX; | ||
| 4402 | } | ||
| 4403 | } else | ||
| 4404 | ✗ | nr = ((ulonglong)table->next_number_field->val_int_offset( | |
| 4405 | ✗ | table->s->rec_buff_length) + | |
| 4406 | 1); | ||
| 4407 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | ha_index_end(); |
| 4408 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | (void)extra(HA_EXTRA_NO_KEYREAD); |
| 4409 | 3 | *first_value = nr; | |
| 4410 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | } |
| 4411 | |||
| 4412 | 18208947 | void handler::ha_release_auto_increment() { | |
| 4413 |
6/8✓ Branch 0 taken 18056285 times.
✓ Branch 1 taken 152662 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 18056263 times.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 22 times.
✗ Branch 7 not taken.
|
18208947 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK || |
| 4414 | (!next_insert_id && !insert_id_for_cur_row)); | ||
| 4415 |
2/2✓ Branch 0 taken 14608526 times.
✓ Branch 1 taken 3600545 times.
|
18208947 | DEBUG_SYNC(ha_thd(), "release_auto_increment"); |
| 4416 | 18209350 | release_auto_increment(); | |
| 4417 | 18209180 | insert_id_for_cur_row = 0; | |
| 4418 | 18209180 | auto_inc_interval_for_cur_row.replace(0, 0, 0); | |
| 4419 | 18209216 | auto_inc_intervals_count = 0; | |
| 4420 |
2/2✓ Branch 0 taken 7078650 times.
✓ Branch 1 taken 11130566 times.
|
18209216 | if (next_insert_id > 0) { |
| 4421 | 7078650 | next_insert_id = 0; | |
| 4422 | /* | ||
| 4423 | this statement used forced auto_increment values if there were some, | ||
| 4424 | wipe them away for other statements. | ||
| 4425 | */ | ||
| 4426 | 7078650 | table->in_use->auto_inc_intervals_forced.clear(); | |
| 4427 | } | ||
| 4428 | 18209222 | } | |
| 4429 | |||
| 4430 | 1974641 | const char *table_case_name(const HA_CREATE_INFO *info, const char *name) { | |
| 4431 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1974641 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1974641 | return ((lower_case_table_names == 2 && info->alias) ? info->alias : name); |
| 4432 | } | ||
| 4433 | |||
| 4434 | /** | ||
| 4435 | Construct and emit duplicate key error message using information | ||
| 4436 | from table's record buffer. | ||
| 4437 | |||
| 4438 | @param table TABLE object which record buffer should be used as | ||
| 4439 | source for column values. | ||
| 4440 | @param key Key description. | ||
| 4441 | @param msg Error message template to which key value should be | ||
| 4442 | added. | ||
| 4443 | @param errflag Flags for my_error() call. | ||
| 4444 | @param org_table_name The original table name (if any) | ||
| 4445 | */ | ||
| 4446 | |||
| 4447 | 257091 | void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag, | |
| 4448 | const char *org_table_name) { | ||
| 4449 | /* Write the duplicated key in the error message */ | ||
| 4450 | char key_buff[MAX_KEY_LENGTH]; | ||
| 4451 | 257091 | String str(key_buff, sizeof(key_buff), system_charset_info); | |
| 4452 | 257091 | std::string key_name; | |
| 4453 | |||
| 4454 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 257090 times.
|
257091 | if (key == nullptr) { |
| 4455 | /* Key is unknown */ | ||
| 4456 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | key_name = "*UNKNOWN*"; |
| 4457 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | str.copy("", 0, system_charset_info); |
| 4458 | |||
| 4459 | } else { | ||
| 4460 | /* Table is opened and defined at this point */ | ||
| 4461 |
1/2✓ Branch 0 taken 257090 times.
✗ Branch 1 not taken.
|
257090 | key_unpack(&str, table, key); |
| 4462 | 257090 | size_t max_length = MYSQL_ERRMSG_SIZE - strlen(msg); | |
| 4463 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 257087 times.
|
257090 | if (str.length() >= max_length) { |
| 4464 | 3 | str.length(max_length - 4); | |
| 4465 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | str.append(STRING_WITH_LEN("...")); |
| 4466 | } | ||
| 4467 | 257090 | str[str.length()] = 0; | |
| 4468 |
2/2✓ Branch 0 taken 1278 times.
✓ Branch 1 taken 255812 times.
|
257090 | if (org_table_name != nullptr) |
| 4469 |
1/2✓ Branch 0 taken 1278 times.
✗ Branch 1 not taken.
|
1278 | key_name = org_table_name; |
| 4470 | else | ||
| 4471 |
1/2✓ Branch 0 taken 255812 times.
✗ Branch 1 not taken.
|
255812 | key_name = table->s->table_name.str; |
| 4472 |
1/2✓ Branch 0 taken 257090 times.
✗ Branch 1 not taken.
|
257090 | key_name += "."; |
| 4473 | |||
| 4474 |
1/2✓ Branch 0 taken 257090 times.
✗ Branch 1 not taken.
|
257090 | key_name += key->name; |
| 4475 | } | ||
| 4476 | |||
| 4477 |
2/4✓ Branch 0 taken 257091 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 257091 times.
✗ Branch 3 not taken.
|
257091 | my_printf_error(ER_DUP_ENTRY, msg, errflag, str.c_ptr(), key_name.c_str()); |
| 4478 | 257091 | } | |
| 4479 | |||
| 4480 | /** | ||
| 4481 | Construct and emit duplicate key error message using information | ||
| 4482 | from table's record buffer. | ||
| 4483 | |||
| 4484 | @sa print_keydup_error(table, key, msg, errflag). | ||
| 4485 | */ | ||
| 4486 | |||
| 4487 | 256256 | void print_keydup_error(TABLE *table, KEY *key, myf errflag, | |
| 4488 | const char *org_table_name) { | ||
| 4489 | 256256 | print_keydup_error(table, key, | |
| 4490 | 256256 | ER_THD(current_thd, ER_DUP_ENTRY_WITH_KEY_NAME), errflag, | |
| 4491 | org_table_name); | ||
| 4492 | 256256 | } | |
| 4493 | |||
| 4494 | /** | ||
| 4495 | This method is used to analyse the error to see whether the error | ||
| 4496 | is ignorable or not. Further comments in header file. | ||
| 4497 | */ | ||
| 4498 | |||
| 4499 | 4457369 | bool handler::is_ignorable_error(int error) { | |
| 4500 |
1/2✓ Branch 0 taken 4457369 times.
✗ Branch 1 not taken.
|
4457369 | DBUG_TRACE; |
| 4501 | |||
| 4502 | // Catch errors that are ignorable | ||
| 4503 |
2/2✓ Branch 0 taken 4456575 times.
✓ Branch 1 taken 794 times.
|
4457369 | switch (error) { |
| 4504 | // Error code 0 is not an error. | ||
| 4505 | 4456575 | case 0: | |
| 4506 | // Dup key errors may be explicitly ignored. | ||
| 4507 | case HA_ERR_FOUND_DUPP_KEY: | ||
| 4508 | case HA_ERR_FOUND_DUPP_UNIQUE: | ||
| 4509 | // Foreign key constraint violations are ignorable. | ||
| 4510 | case HA_ERR_ROW_IS_REFERENCED: | ||
| 4511 | case HA_ERR_NO_REFERENCED_ROW: | ||
| 4512 | 4456575 | return true; | |
| 4513 | } | ||
| 4514 | |||
| 4515 | // Default is that an error is not ignorable. | ||
| 4516 | 794 | return false; | |
| 4517 | 4457369 | } | |
| 4518 | |||
| 4519 | /** | ||
| 4520 | This method is used to analyse the error to see whether the error | ||
| 4521 | is fatal or not. Further comments in header file. | ||
| 4522 | */ | ||
| 4523 | |||
| 4524 | 256639 | bool handler::is_fatal_error(int error) { | |
| 4525 |
1/2✓ Branch 0 taken 256639 times.
✗ Branch 1 not taken.
|
256639 | DBUG_TRACE; |
| 4526 | |||
| 4527 | // No ignorable errors are fatal | ||
| 4528 |
3/4✓ Branch 0 taken 256639 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 256168 times.
✓ Branch 3 taken 471 times.
|
256639 | if (is_ignorable_error(error)) return false; |
| 4529 | |||
| 4530 | // Catch errors that are not fatal | ||
| 4531 |
2/3✓ Branch 0 taken 160 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 311 times.
|
471 | switch (error) { |
| 4532 | /* | ||
| 4533 | Deadlock and lock timeout cause transaction/statement rollback so | ||
| 4534 | that THD::is_fatal_sub_stmt_error will be set. This means that they will | ||
| 4535 | not be possible to handle by stored program handlers inside stored | ||
| 4536 | functions and triggers even if non-fatal. | ||
| 4537 | */ | ||
| 4538 | 160 | case HA_ERR_LOCK_WAIT_TIMEOUT: | |
| 4539 | case HA_ERR_LOCK_DEADLOCK: | ||
| 4540 | 160 | return false; | |
| 4541 | |||
| 4542 | ✗ | case HA_ERR_NULL_IN_SPATIAL: | |
| 4543 | ✗ | return false; | |
| 4544 | } | ||
| 4545 | |||
| 4546 | // Default is that an error is fatal | ||
| 4547 | 311 | return true; | |
| 4548 | 256639 | } | |
| 4549 | |||
| 4550 | /** | ||
| 4551 | Print error that we got from handler function. | ||
| 4552 | |||
| 4553 | @note | ||
| 4554 | In case of delete table it's only safe to use the following parts of | ||
| 4555 | the 'table' structure: | ||
| 4556 | - table->s->path | ||
| 4557 | - table->alias | ||
| 4558 | */ | ||
| 4559 | 258304 | void handler::print_error(int error, myf errflag) { | |
| 4560 |
1/2✓ Branch 0 taken 258305 times.
✗ Branch 1 not taken.
|
258304 | THD *thd = current_thd; |
| 4561 | 258305 | Foreign_key_error_handler foreign_key_error_handler(thd, this); | |
| 4562 | |||
| 4563 |
1/2✓ Branch 0 taken 258306 times.
✗ Branch 1 not taken.
|
258305 | DBUG_TRACE; |
| 4564 |
3/8✓ Branch 0 taken 258306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 258306 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 258306 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
258306 | DBUG_PRINT("enter", ("error: %d", error)); |
| 4565 | |||
| 4566 | 258305 | int textno = ER_GET_ERRNO; | |
| 4567 |
40/60✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 54 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 255846 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 24 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 9 times.
✓ Branch 13 taken 14 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 11 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 11 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 39 times.
✓ Branch 20 taken 172 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 427 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 232 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 17 times.
✓ Branch 27 taken 90 times.
✓ Branch 28 taken 113 times.
✓ Branch 29 taken 13 times.
✓ Branch 30 taken 207 times.
✓ Branch 31 taken 8 times.
✗ Branch 32 not taken.
✓ Branch 33 taken 13 times.
✗ Branch 34 not taken.
✓ Branch 35 taken 39 times.
✓ Branch 36 taken 17 times.
✓ Branch 37 taken 25 times.
✓ Branch 38 taken 6 times.
✓ Branch 39 taken 12 times.
✓ Branch 40 taken 28 times.
✓ Branch 41 taken 12 times.
✓ Branch 42 taken 12 times.
✗ Branch 43 not taken.
✓ Branch 44 taken 169 times.
✗ Branch 45 not taken.
✓ Branch 46 taken 10 times.
✓ Branch 47 taken 5 times.
✗ Branch 48 not taken.
✓ Branch 49 taken 1 times.
✓ Branch 50 taken 54 times.
✓ Branch 51 taken 8 times.
✓ Branch 52 taken 20 times.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✓ Branch 55 taken 2 times.
✓ Branch 56 taken 3 times.
✓ Branch 57 taken 26 times.
✗ Branch 58 not taken.
✓ Branch 59 taken 533 times.
|
258305 | switch (error) { |
| 4568 | ✗ | case EACCES: | |
| 4569 | ✗ | textno = ER_OPEN_AS_READONLY; | |
| 4570 | ✗ | break; | |
| 4571 | ✗ | case EAGAIN: | |
| 4572 | ✗ | textno = ER_FILE_USED; | |
| 4573 | ✗ | break; | |
| 4574 | 17 | case ENOENT: { | |
| 4575 | char errbuf[MYSYS_STRERROR_SIZE]; | ||
| 4576 | 17 | textno = ER_FILE_NOT_FOUND; | |
| 4577 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | my_error(textno, errflag, table_share->table_name.str, error, |
| 4578 | my_strerror(errbuf, sizeof(errbuf), error)); | ||
| 4579 | 17 | } break; | |
| 4580 | 54 | case HA_ERR_KEY_NOT_FOUND: | |
| 4581 | case HA_ERR_NO_ACTIVE_RECORD: | ||
| 4582 | case HA_ERR_RECORD_DELETED: | ||
| 4583 | case HA_ERR_END_OF_FILE: | ||
| 4584 | 54 | textno = ER_KEY_NOT_FOUND; | |
| 4585 | 54 | break; | |
| 4586 | 2 | case HA_ERR_WRONG_MRG_TABLE_DEF: | |
| 4587 | 2 | textno = ER_WRONG_MRG_TABLE; | |
| 4588 | 2 | break; | |
| 4589 | 255846 | case HA_ERR_FOUND_DUPP_KEY: { | |
| 4590 |
2/4✓ Branch 0 taken 255846 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 255846 times.
✗ Branch 3 not taken.
|
255846 | uint key_nr = table ? get_dup_key(error) : -1; |
| 4591 |
2/2✓ Branch 0 taken 255812 times.
✓ Branch 1 taken 34 times.
|
255846 | if ((int)key_nr >= 0) { |
| 4592 |
2/4✓ Branch 0 taken 255812 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 255812 times.
✗ Branch 3 not taken.
|
511624 | print_keydup_error( |
| 4593 | 255812 | table, key_nr == MAX_KEY ? nullptr : &table->key_info[key_nr], | |
| 4594 | errflag); | ||
| 4595 | 255812 | return; | |
| 4596 | } | ||
| 4597 | 34 | textno = ER_DUP_KEY; | |
| 4598 | 34 | break; | |
| 4599 | } | ||
| 4600 | 4 | case HA_ERR_FOREIGN_DUPLICATE_KEY: { | |
| 4601 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 4602 | |||
| 4603 | char rec_buf[MAX_KEY_LENGTH]; | ||
| 4604 | 4 | String rec(rec_buf, sizeof(rec_buf), system_charset_info); | |
| 4605 | /* Table is opened and defined at this point */ | ||
| 4606 | |||
| 4607 | /* | ||
| 4608 | Just print the subset of fields that are part of the first index, | ||
| 4609 | printing the whole row from there is not easy. | ||
| 4610 | */ | ||
| 4611 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | key_unpack(&rec, table, &table->key_info[0]); |
| 4612 | |||
| 4613 | char child_table_name[NAME_LEN + 1]; | ||
| 4614 | char child_key_name[NAME_LEN + 1]; | ||
| 4615 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | if (get_foreign_dup_key(child_table_name, sizeof(child_table_name), |
| 4616 | child_key_name, sizeof(child_key_name))) { | ||
| 4617 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO, errflag, |
| 4618 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | table_share->table_name.str, rec.c_ptr_safe(), |
| 4619 | child_table_name, child_key_name); | ||
| 4620 | } else { | ||
| 4621 | ✗ | my_error(ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO, errflag, | |
| 4622 | ✗ | table_share->table_name.str, rec.c_ptr_safe()); | |
| 4623 | } | ||
| 4624 | 4 | return; | |
| 4625 | 4 | } | |
| 4626 | ✗ | case HA_ERR_NULL_IN_SPATIAL: | |
| 4627 | ✗ | my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, errflag); | |
| 4628 | ✗ | return; | |
| 4629 | ✗ | case HA_ERR_FOUND_DUPP_UNIQUE: | |
| 4630 | ✗ | textno = ER_DUP_UNIQUE; | |
| 4631 | ✗ | break; | |
| 4632 | ✗ | case HA_ERR_RECORD_CHANGED: | |
| 4633 | ✗ | textno = ER_CHECKREAD; | |
| 4634 | ✗ | break; | |
| 4635 | 24 | case HA_ERR_CRASHED: | |
| 4636 | 24 | textno = ER_NOT_KEYFILE; | |
| 4637 | 24 | break; | |
| 4638 | ✗ | case HA_ERR_WRONG_IN_RECORD: | |
| 4639 | ✗ | textno = ER_CRASHED_ON_USAGE; | |
| 4640 | ✗ | break; | |
| 4641 | 9 | case HA_ERR_CRASHED_ON_USAGE: | |
| 4642 | 9 | textno = ER_CRASHED_ON_USAGE; | |
| 4643 | 9 | break; | |
| 4644 | 14 | case HA_ERR_NOT_A_TABLE: | |
| 4645 | 14 | textno = error; | |
| 4646 | 14 | break; | |
| 4647 | ✗ | case HA_ERR_CRASHED_ON_REPAIR: | |
| 4648 | ✗ | textno = ER_CRASHED_ON_REPAIR; | |
| 4649 | ✗ | break; | |
| 4650 | 11 | case HA_ERR_OUT_OF_MEM: | |
| 4651 | 11 | textno = ER_OUT_OF_RESOURCES; | |
| 4652 | 11 | break; | |
| 4653 | ✗ | case HA_ERR_SE_OUT_OF_MEMORY: | |
| 4654 | ✗ | my_error(ER_ENGINE_OUT_OF_MEMORY, errflag, table->file->table_type()); | |
| 4655 | ✗ | return; | |
| 4656 | 11 | case HA_ERR_WRONG_COMMAND: | |
| 4657 | 11 | textno = ER_ILLEGAL_HA; | |
| 4658 | 11 | break; | |
| 4659 | ✗ | case HA_ERR_OLD_FILE: | |
| 4660 | ✗ | textno = ER_OLD_KEYFILE; | |
| 4661 | ✗ | break; | |
| 4662 | 39 | case HA_ERR_UNSUPPORTED: | |
| 4663 | 39 | textno = ER_UNSUPPORTED_EXTENSION; | |
| 4664 | 39 | break; | |
| 4665 | 172 | case HA_ERR_RECORD_FILE_FULL: | |
| 4666 | case HA_ERR_INDEX_FILE_FULL: { | ||
| 4667 | 172 | textno = ER_RECORD_FILE_FULL; | |
| 4668 | /* Write the error message to error log */ | ||
| 4669 |
8/16✓ Branch 0 taken 172 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 172 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 172 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 172 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 172 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 172 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 172 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 172 times.
✗ Branch 15 not taken.
|
172 | LogErr(ERROR_LEVEL, ER_SERVER_RECORD_FILE_FULL, |
| 4670 | table_share->table_name.str); | ||
| 4671 | 172 | break; | |
| 4672 | } | ||
| 4673 | ✗ | case HA_ERR_DISK_FULL_NOWAIT: { | |
| 4674 | ✗ | textno = ER_DISK_FULL_NOWAIT; | |
| 4675 | /* Write the error message to error log */ | ||
| 4676 | ✗ | LogErr(ERROR_LEVEL, ER_SERVER_DISK_FULL_NOWAIT, | |
| 4677 | table_share->table_name.str); | ||
| 4678 | ✗ | break; | |
| 4679 | } | ||
| 4680 | 427 | case HA_ERR_LOCK_WAIT_TIMEOUT: | |
| 4681 | 427 | textno = ER_LOCK_WAIT_TIMEOUT; | |
| 4682 | 427 | break; | |
| 4683 | ✗ | case HA_ERR_LOCK_TABLE_FULL: | |
| 4684 | ✗ | textno = ER_LOCK_TABLE_FULL; | |
| 4685 | ✗ | break; | |
| 4686 | 232 | case HA_ERR_LOCK_DEADLOCK: | |
| 4687 | 232 | textno = ER_LOCK_DEADLOCK; | |
| 4688 | 232 | break; | |
| 4689 | ✗ | case HA_ERR_READ_ONLY_TRANSACTION: | |
| 4690 | ✗ | textno = ER_READ_ONLY_TRANSACTION; | |
| 4691 | ✗ | break; | |
| 4692 | 17 | case HA_ERR_CANNOT_ADD_FOREIGN: | |
| 4693 | 17 | textno = ER_CANNOT_ADD_FOREIGN; | |
| 4694 | 17 | break; | |
| 4695 | 90 | case HA_ERR_ROW_IS_REFERENCED: { | |
| 4696 | 90 | String str; | |
| 4697 | /* | ||
| 4698 | Manipulate the error message while handling the error | ||
| 4699 | condition based on the access check. | ||
| 4700 | */ | ||
| 4701 |
1/2✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
|
90 | thd->push_internal_handler(&foreign_key_error_handler); |
| 4702 |
1/2✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
|
90 | get_error_message(error, &str); |
| 4703 |
2/4✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
|
90 | my_error(ER_ROW_IS_REFERENCED_2, errflag, str.c_ptr_safe()); |
| 4704 |
1/2✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
|
90 | thd->pop_internal_handler(); |
| 4705 | 90 | return; | |
| 4706 | 90 | } | |
| 4707 | 113 | case HA_ERR_NO_REFERENCED_ROW: { | |
| 4708 | 113 | String str; | |
| 4709 | /* | ||
| 4710 | Manipulate the error message while handling the error | ||
| 4711 | condition based on the access check. | ||
| 4712 | */ | ||
| 4713 |
1/2✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
|
113 | thd->push_internal_handler(&foreign_key_error_handler); |
| 4714 |
1/2✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
|
113 | get_error_message(error, &str); |
| 4715 |
2/4✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 113 times.
✗ Branch 3 not taken.
|
113 | my_error(ER_NO_REFERENCED_ROW_2, errflag, str.c_ptr_safe()); |
| 4716 |
1/2✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
|
113 | thd->pop_internal_handler(); |
| 4717 | 113 | return; | |
| 4718 | 113 | } | |
| 4719 | 13 | case HA_ERR_TABLE_DEF_CHANGED: | |
| 4720 | 13 | textno = ER_TABLE_DEF_CHANGED; | |
| 4721 | 13 | break; | |
| 4722 | 207 | case HA_ERR_NO_SUCH_TABLE: | |
| 4723 | 207 | my_error(ER_NO_SUCH_TABLE, errflag, table_share->db.str, | |
| 4724 |
1/2✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
|
207 | table_share->table_name.str); |
| 4725 | 207 | return; | |
| 4726 | 8 | case HA_ERR_RBR_LOGGING_FAILED: | |
| 4727 | 8 | textno = ER_BINLOG_ROW_LOGGING_FAILED; | |
| 4728 | 8 | break; | |
| 4729 | ✗ | case HA_ERR_DROP_INDEX_FK: { | |
| 4730 | ✗ | const char *ptr = "???"; | |
| 4731 | ✗ | uint key_nr = table ? get_dup_key(error) : -1; | |
| 4732 | ✗ | if ((int)key_nr >= 0 && key_nr != MAX_KEY) | |
| 4733 | ✗ | ptr = table->key_info[key_nr].name; | |
| 4734 | ✗ | my_error(ER_DROP_INDEX_FK, errflag, ptr); | |
| 4735 | ✗ | return; | |
| 4736 | } | ||
| 4737 | 13 | case HA_ERR_TABLE_NEEDS_UPGRADE: | |
| 4738 | 13 | textno = ER_TABLE_NEEDS_UPGRADE; | |
| 4739 | 13 | break; | |
| 4740 | ✗ | case HA_ERR_NO_PARTITION_FOUND: | |
| 4741 | ✗ | textno = ER_WRONG_PARTITION_NAME; | |
| 4742 | ✗ | break; | |
| 4743 | 39 | case HA_ERR_TABLE_READONLY: | |
| 4744 | 39 | textno = ER_OPEN_AS_READONLY; | |
| 4745 | 39 | break; | |
| 4746 | 17 | case HA_ERR_AUTOINC_READ_FAILED: | |
| 4747 | 17 | textno = ER_AUTOINC_READ_FAILED; | |
| 4748 | 17 | break; | |
| 4749 | 25 | case HA_ERR_AUTOINC_ERANGE: | |
| 4750 | 25 | textno = ER_WARN_DATA_OUT_OF_RANGE; | |
| 4751 | 25 | break; | |
| 4752 | 6 | case HA_ERR_TOO_MANY_CONCURRENT_TRXS: | |
| 4753 | 6 | textno = ER_TOO_MANY_CONCURRENT_TRXS; | |
| 4754 | 6 | break; | |
| 4755 | 12 | case HA_ERR_INDEX_COL_TOO_LONG: | |
| 4756 | 12 | textno = ER_INDEX_COLUMN_TOO_LONG; | |
| 4757 | 12 | break; | |
| 4758 | 28 | case HA_ERR_NOT_IN_LOCK_PARTITIONS: | |
| 4759 | 28 | textno = ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET; | |
| 4760 | 28 | break; | |
| 4761 | 12 | case HA_ERR_INDEX_CORRUPT: | |
| 4762 | 12 | textno = ER_INDEX_CORRUPT; | |
| 4763 | 12 | break; | |
| 4764 | 12 | case HA_ERR_UNDO_REC_TOO_BIG: | |
| 4765 | 12 | textno = ER_UNDO_RECORD_TOO_BIG; | |
| 4766 | 12 | break; | |
| 4767 | ✗ | case HA_ERR_TABLE_IN_FK_CHECK: | |
| 4768 | ✗ | textno = ER_TABLE_IN_FK_CHECK; | |
| 4769 | ✗ | break; | |
| 4770 | 169 | case HA_WRONG_CREATE_OPTION: | |
| 4771 | 169 | textno = ER_ILLEGAL_HA; | |
| 4772 | 169 | break; | |
| 4773 | ✗ | case HA_MISSING_CREATE_OPTION: { | |
| 4774 | ✗ | const char *engine = table_type(); | |
| 4775 | ✗ | my_error(ER_MISSING_HA_CREATE_OPTION, errflag, engine); | |
| 4776 | ✗ | return; | |
| 4777 | } | ||
| 4778 | 10 | case HA_ERR_TOO_MANY_FIELDS: | |
| 4779 | 10 | textno = ER_TOO_MANY_FIELDS; | |
| 4780 | 10 | break; | |
| 4781 | 5 | case HA_ERR_INNODB_READ_ONLY: | |
| 4782 | 5 | textno = ER_INNODB_READ_ONLY; | |
| 4783 | 5 | break; | |
| 4784 | ✗ | case HA_ERR_TEMP_FILE_WRITE_FAILURE: | |
| 4785 | ✗ | textno = ER_TEMP_FILE_WRITE_FAILURE; | |
| 4786 | ✗ | break; | |
| 4787 | 1 | case HA_ERR_INNODB_FORCED_RECOVERY: | |
| 4788 | 1 | textno = ER_INNODB_FORCED_RECOVERY; | |
| 4789 | 1 | break; | |
| 4790 | 54 | case HA_ERR_TABLE_CORRUPT: | |
| 4791 | 54 | my_error(ER_TABLE_CORRUPT, errflag, table_share->db.str, | |
| 4792 |
1/2✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
|
54 | table_share->table_name.str); |
| 4793 | 54 | return; | |
| 4794 | 8 | case HA_ERR_QUERY_INTERRUPTED: | |
| 4795 | 8 | textno = ER_QUERY_INTERRUPTED; | |
| 4796 | 8 | break; | |
| 4797 | 20 | case HA_ERR_TABLESPACE_MISSING: { | |
| 4798 | char errbuf[MYSYS_STRERROR_SIZE]; | ||
| 4799 | 20 | snprintf(errbuf, MYSYS_STRERROR_SIZE, "`%s`.`%s`", table_share->db.str, | |
| 4800 | 20 | table_share->table_name.str); | |
| 4801 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | my_error(ER_TABLESPACE_MISSING, errflag, errbuf, error); |
| 4802 | 20 | return; | |
| 4803 | } | ||
| 4804 | ✗ | case HA_ERR_TABLESPACE_IS_NOT_EMPTY: | |
| 4805 | ✗ | my_error(ER_TABLESPACE_IS_NOT_EMPTY, errflag, table_share->db.str, | |
| 4806 | ✗ | table_share->table_name.str); | |
| 4807 | ✗ | return; | |
| 4808 | ✗ | case HA_ERR_WRONG_FILE_NAME: | |
| 4809 | ✗ | my_error(ER_WRONG_FILE_NAME, errflag, table_share->table_name.str); | |
| 4810 | ✗ | return; | |
| 4811 | 2 | case HA_ERR_NOT_ALLOWED_COMMAND: | |
| 4812 | 2 | textno = ER_NOT_ALLOWED_COMMAND; | |
| 4813 | 2 | break; | |
| 4814 | 3 | case HA_ERR_NO_SESSION_TEMP: | |
| 4815 | 3 | textno = ER_NO_SESSION_TEMP; | |
| 4816 | 3 | break; | |
| 4817 | 26 | case HA_ERR_WRONG_TABLE_NAME: | |
| 4818 | 26 | textno = ER_WRONG_TABLE_NAME; | |
| 4819 | 26 | break; | |
| 4820 | ✗ | case HA_ERR_TOO_LONG_PATH: | |
| 4821 | ✗ | textno = ER_TABLE_NAME_CAUSES_TOO_LONG_PATH; | |
| 4822 | ✗ | break; | |
| 4823 | 533 | default: { | |
| 4824 | /* The error was "unknown" to this function. | ||
| 4825 | Ask handler if it has got a message for this error */ | ||
| 4826 | 533 | String str; | |
| 4827 |
1/2✓ Branch 0 taken 533 times.
✗ Branch 1 not taken.
|
533 | bool temporary = get_error_message(error, &str); |
| 4828 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 528 times.
|
533 | if (!str.is_empty()) { |
| 4829 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | const char *engine = table_type(); |
| 4830 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (temporary) |
| 4831 | ✗ | my_error(ER_GET_TEMPORARY_ERRMSG, errflag, error, str.ptr(), engine); | |
| 4832 | else | ||
| 4833 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | my_error(ER_GET_ERRMSG, errflag, error, str.ptr(), engine); |
| 4834 | } else { | ||
| 4835 | char errbuf[MYSQL_ERRMSG_SIZE]; | ||
| 4836 |
2/4✓ Branch 0 taken 528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 528 times.
✗ Branch 3 not taken.
|
528 | my_error(ER_GET_ERRNO, errflag, error, |
| 4837 | my_strerror(errbuf, MYSQL_ERRMSG_SIZE, error)); | ||
| 4838 | } | ||
| 4839 | 533 | return; | |
| 4840 | 533 | } | |
| 4841 | } | ||
| 4842 |
2/2✓ Branch 0 taken 1455 times.
✓ Branch 1 taken 17 times.
|
1472 | if (textno != ER_FILE_NOT_FOUND) |
| 4843 |
1/2✓ Branch 0 taken 1456 times.
✗ Branch 1 not taken.
|
1455 | my_error(textno, errflag, table_share->table_name.str, error); |
| 4844 |
4/4✓ Branch 0 taken 1472 times.
✓ Branch 1 taken 256833 times.
✓ Branch 2 taken 1472 times.
✓ Branch 3 taken 256833 times.
|
515139 | } |
| 4845 | |||
| 4846 | /** | ||
| 4847 | Return an error message specific to this handler. | ||
| 4848 | |||
| 4849 | @param error error code previously returned by handler | ||
| 4850 | @param buf pointer to String where to add error message | ||
| 4851 | |||
| 4852 | @return | ||
| 4853 | Returns true if this is a temporary error | ||
| 4854 | */ | ||
| 4855 | 185 | bool handler::get_error_message(int error [[maybe_unused]], | |
| 4856 | String *buf [[maybe_unused]]) { | ||
| 4857 | 185 | return false; | |
| 4858 | } | ||
| 4859 | |||
| 4860 | /** | ||
| 4861 | Check for incompatible collation changes. | ||
| 4862 | |||
| 4863 | @retval | ||
| 4864 | HA_ADMIN_NEEDS_UPGRADE Table may have data requiring upgrade. | ||
| 4865 | @retval | ||
| 4866 | 0 No upgrade required. | ||
| 4867 | */ | ||
| 4868 | |||
| 4869 | 1034 | int handler::check_collation_compatibility() { | |
| 4870 | 1034 | ulong mysql_version = table->s->mysql_version; | |
| 4871 | |||
| 4872 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1034 times.
|
1034 | if (mysql_version < 50124) { |
| 4873 | ✗ | KEY *key = table->key_info; | |
| 4874 | ✗ | KEY *key_end = key + table->s->keys; | |
| 4875 | ✗ | for (; key < key_end; key++) { | |
| 4876 | ✗ | KEY_PART_INFO *key_part = key->key_part; | |
| 4877 | ✗ | KEY_PART_INFO *key_part_end = key_part + key->user_defined_key_parts; | |
| 4878 | ✗ | for (; key_part < key_part_end; key_part++) { | |
| 4879 | ✗ | if (!key_part->fieldnr) continue; | |
| 4880 | ✗ | Field *field = table->field[key_part->fieldnr - 1]; | |
| 4881 | ✗ | uint cs_number = field->charset()->number; | |
| 4882 | ✗ | if ((mysql_version < 50048 && | |
| 4883 | ✗ | (cs_number == 11 || /* ascii_general_ci - bug #29499, bug #27562 */ | |
| 4884 | ✗ | cs_number == 41 || /* latin7_general_ci - bug #29461 */ | |
| 4885 | ✗ | cs_number == 42 || /* latin7_general_cs - bug #29461 */ | |
| 4886 | ✗ | cs_number == 20 || /* latin7_estonian_cs - bug #29461 */ | |
| 4887 | ✗ | cs_number == 21 || /* latin2_hungarian_ci - bug #29461 */ | |
| 4888 | ✗ | cs_number == 22 || /* koi8u_general_ci - bug #29461 */ | |
| 4889 | ✗ | cs_number == 23 || /* cp1251_ukrainian_ci - bug #29461 */ | |
| 4890 | ✗ | cs_number == 26)) || /* cp1250_general_ci - bug #29461 */ | |
| 4891 | ✗ | (mysql_version < 50124 && | |
| 4892 | ✗ | (cs_number == 33 || /* utf8mb3_general_ci - bug #27877 */ | |
| 4893 | cs_number == 35))) /* ucs2_general_ci - bug #27877 */ | ||
| 4894 | ✗ | return HA_ADMIN_NEEDS_UPGRADE; | |
| 4895 | } | ||
| 4896 | } | ||
| 4897 | } | ||
| 4898 | 1034 | return 0; | |
| 4899 | } | ||
| 4900 | |||
| 4901 | 1034 | int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt) { | |
| 4902 | int error; | ||
| 4903 | KEY *keyinfo, *keyend; | ||
| 4904 | KEY_PART_INFO *keypart, *keypartend; | ||
| 4905 | |||
| 4906 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1034 times.
|
1034 | if (!table->s->mysql_version) { |
| 4907 | /* check for blob-in-key error */ | ||
| 4908 | ✗ | keyinfo = table->key_info; | |
| 4909 | ✗ | keyend = table->key_info + table->s->keys; | |
| 4910 | ✗ | for (; keyinfo < keyend; keyinfo++) { | |
| 4911 | ✗ | keypart = keyinfo->key_part; | |
| 4912 | ✗ | keypartend = keypart + keyinfo->user_defined_key_parts; | |
| 4913 | ✗ | for (; keypart < keypartend; keypart++) { | |
| 4914 | ✗ | if (!keypart->fieldnr) continue; | |
| 4915 | ✗ | Field *field = table->field[keypart->fieldnr - 1]; | |
| 4916 | ✗ | if (field->type() == MYSQL_TYPE_BLOB) { | |
| 4917 | ✗ | if (check_opt->sql_flags & TT_FOR_UPGRADE) | |
| 4918 | ✗ | check_opt->flags = T_MEDIUM; | |
| 4919 | ✗ | return HA_ADMIN_NEEDS_CHECK; | |
| 4920 | } | ||
| 4921 | } | ||
| 4922 | } | ||
| 4923 | } | ||
| 4924 | |||
| 4925 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1034 times.
|
1034 | if ((error = check_collation_compatibility())) return error; |
| 4926 | |||
| 4927 | 1034 | return check_for_upgrade(check_opt); | |
| 4928 | } | ||
| 4929 | |||
| 4930 | // Function identifies any old data type present in table. | ||
| 4931 | 6087 | int check_table_for_old_types(const TABLE *table, bool check_temporal_upgrade) { | |
| 4932 | Field **field; | ||
| 4933 | |||
| 4934 |
2/2✓ Branch 0 taken 30715 times.
✓ Branch 1 taken 6083 times.
|
36798 | for (field = table->field; (*field); field++) { |
| 4935 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30715 times.
|
30715 | if (table->s->mysql_version == 0) // prior to MySQL 5.0 |
| 4936 | { | ||
| 4937 | /* check for bad DECIMAL field */ | ||
| 4938 | ✗ | if ((*field)->type() == MYSQL_TYPE_NEWDECIMAL) { | |
| 4939 | ✗ | return HA_ADMIN_NEEDS_ALTER; | |
| 4940 | } | ||
| 4941 | ✗ | if ((*field)->type() == MYSQL_TYPE_VAR_STRING) { | |
| 4942 | ✗ | return HA_ADMIN_NEEDS_ALTER; | |
| 4943 | } | ||
| 4944 | } | ||
| 4945 | |||
| 4946 | /* | ||
| 4947 | Check for old DECIMAL field. | ||
| 4948 | |||
| 4949 | Above check does not take into account for pre 5.0 decimal types which can | ||
| 4950 | be present in the data directory if user did in-place upgrade from | ||
| 4951 | mysql-4.1 to mysql-5.0. | ||
| 4952 | */ | ||
| 4953 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 30713 times.
|
30715 | if ((*field)->type() == MYSQL_TYPE_DECIMAL) { |
| 4954 | 2 | return HA_ADMIN_NEEDS_DUMP_UPGRADE; | |
| 4955 | } | ||
| 4956 | |||
| 4957 |
4/6✓ Branch 0 taken 9 times.
✓ Branch 1 taken 30704 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 30713 times.
|
30713 | if ((*field)->type() == MYSQL_TYPE_YEAR && (*field)->field_length == 2) |
| 4958 | ✗ | return HA_ADMIN_NEEDS_ALTER; // obsolete YEAR(2) type | |
| 4959 | |||
| 4960 |
1/2✓ Branch 0 taken 30713 times.
✗ Branch 1 not taken.
|
30713 | if (check_temporal_upgrade) { |
| 4961 | 30713 | if (((*field)->real_type() == MYSQL_TYPE_TIME) || | |
| 4962 |
5/6✓ Branch 0 taken 30711 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 30711 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 30711 times.
|
61424 | ((*field)->real_type() == MYSQL_TYPE_DATETIME) || |
| 4963 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30711 times.
|
30711 | ((*field)->real_type() == MYSQL_TYPE_TIMESTAMP)) |
| 4964 | 2 | return HA_ADMIN_NEEDS_ALTER; | |
| 4965 | } | ||
| 4966 | } | ||
| 4967 | 6083 | return 0; | |
| 4968 | } | ||
| 4969 | |||
| 4970 | /** | ||
| 4971 | @return | ||
| 4972 | key if error because of duplicated keys | ||
| 4973 | */ | ||
| 4974 | 928022 | uint handler::get_dup_key(int error) { | |
| 4975 |
3/4✓ Branch 0 taken 926756 times.
✓ Branch 1 taken 1266 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 926756 times.
|
928022 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 4976 |
1/2✓ Branch 0 taken 928022 times.
✗ Branch 1 not taken.
|
928022 | DBUG_TRACE; |
| 4977 | 928022 | table->file->errkey = (uint)-1; | |
| 4978 |
4/6✓ Branch 0 taken 7 times.
✓ Branch 1 taken 928015 times.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
928022 | if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE || |
| 4979 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | error == HA_ERR_NULL_IN_SPATIAL || error == HA_ERR_DROP_INDEX_FK) |
| 4980 |
1/2✓ Branch 0 taken 928015 times.
✗ Branch 1 not taken.
|
928015 | table->file->info(HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK); |
| 4981 | 928022 | return table->file->errkey; | |
| 4982 | 928022 | } | |
| 4983 | |||
| 4984 | ✗ | bool handler::get_foreign_dup_key(char *, uint, char *, uint) { | |
| 4985 | ✗ | assert(false); | |
| 4986 | return (false); | ||
| 4987 | } | ||
| 4988 | |||
| 4989 | 2966 | int handler::delete_table(const char *name, const dd::Table *) { | |
| 4990 | 2966 | int saved_error = 0; | |
| 4991 | 2966 | int error = 0; | |
| 4992 | 2966 | int enoent_or_zero = ENOENT; // Error if no file was deleted | |
| 4993 | char buff[FN_REFLEN]; | ||
| 4994 | const char **start_ext; | ||
| 4995 | |||
| 4996 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2966 times.
|
2966 | assert(m_lock_type == F_UNLCK); |
| 4997 | |||
| 4998 |
2/2✓ Branch 0 taken 119 times.
✓ Branch 1 taken 2847 times.
|
2966 | if (!(start_ext = ht->file_extensions)) return 0; |
| 4999 |
2/2✓ Branch 0 taken 4319 times.
✓ Branch 1 taken 2847 times.
|
7166 | for (const char **ext = start_ext; *ext; ext++) { |
| 5000 |
1/2✓ Branch 0 taken 4319 times.
✗ Branch 1 not taken.
|
4319 | fn_format(buff, name, "", *ext, MY_UNPACK_FILENAME | MY_APPEND_EXT); |
| 5001 |
3/4✓ Branch 0 taken 4319 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4316 times.
|
4319 | if (mysql_file_delete_with_symlink(key_file_misc, buff, MYF(0))) { |
| 5002 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
3 | if (my_errno() != ENOENT) { |
| 5003 | /* | ||
| 5004 | If error on the first existing file, return the error. | ||
| 5005 | Otherwise delete as much as possible. | ||
| 5006 | */ | ||
| 5007 | ✗ | if (enoent_or_zero) return my_errno(); | |
| 5008 | ✗ | saved_error = my_errno(); | |
| 5009 | } | ||
| 5010 | } else | ||
| 5011 | 4316 | enoent_or_zero = 0; // No error for ENOENT | |
| 5012 | 4319 | error = enoent_or_zero; | |
| 5013 | } | ||
| 5014 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2847 times.
|
2847 | return saved_error ? saved_error : error; |
| 5015 | } | ||
| 5016 | |||
| 5017 | 1235 | int handler::rename_table(const char *from, const char *to, | |
| 5018 | const dd::Table *from_table_def [[maybe_unused]], | ||
| 5019 | dd::Table *to_table_def [[maybe_unused]]) { | ||
| 5020 | 1235 | int error = 0; | |
| 5021 | const char **ext, **start_ext; | ||
| 5022 | |||
| 5023 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 1193 times.
|
1235 | if (!(start_ext = ht->file_extensions)) return 0; |
| 5024 |
2/2✓ Branch 0 taken 2357 times.
✓ Branch 1 taken 1193 times.
|
3550 | for (ext = start_ext; *ext; ext++) { |
| 5025 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2357 times.
|
2357 | if (rename_file_ext(from, to, *ext)) { |
| 5026 | ✗ | error = my_errno(); | |
| 5027 | ✗ | if (error != ENOENT) break; | |
| 5028 | ✗ | error = 0; | |
| 5029 | } | ||
| 5030 | } | ||
| 5031 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1193 times.
|
1193 | if (error) { |
| 5032 | /* Try to revert the rename. Ignore errors. */ | ||
| 5033 | ✗ | for (; ext >= start_ext; ext--) rename_file_ext(to, from, *ext); | |
| 5034 | } | ||
| 5035 | 1193 | return error; | |
| 5036 | } | ||
| 5037 | |||
| 5038 | 483017 | void handler::drop_table(const char *name) { | |
| 5039 | 483017 | close(); | |
| 5040 | 483017 | delete_table(name, nullptr); | |
| 5041 | 483016 | } | |
| 5042 | |||
| 5043 | /** | ||
| 5044 | Performs checks upon the table. | ||
| 5045 | |||
| 5046 | @param thd thread doing CHECK TABLE operation | ||
| 5047 | @param check_opt options from the parser | ||
| 5048 | |||
| 5049 | @retval | ||
| 5050 | HA_ADMIN_OK Successful upgrade | ||
| 5051 | @retval | ||
| 5052 | HA_ADMIN_NEEDS_UPGRADE Table has structures requiring upgrade | ||
| 5053 | @retval | ||
| 5054 | HA_ADMIN_NEEDS_ALTER Table has structures requiring ALTER TABLE | ||
| 5055 | @retval | ||
| 5056 | HA_ADMIN_NOT_IMPLEMENTED | ||
| 5057 | */ | ||
| 5058 | 11031 | int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) { | |
| 5059 | int error; | ||
| 5060 |
3/4✓ Branch 0 taken 11021 times.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11021 times.
|
11031 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 5061 | |||
| 5062 |
2/2✓ Branch 0 taken 10860 times.
✓ Branch 1 taken 171 times.
|
11031 | if ((table->s->mysql_version >= MYSQL_VERSION_ID) && |
| 5063 |
2/2✓ Branch 0 taken 8370 times.
✓ Branch 1 taken 2490 times.
|
10860 | (check_opt->sql_flags & TT_FOR_UPGRADE)) |
| 5064 | 8370 | return 0; | |
| 5065 | |||
| 5066 |
2/2✓ Branch 0 taken 171 times.
✓ Branch 1 taken 2490 times.
|
2661 | if (table->s->mysql_version < MYSQL_VERSION_ID) { |
| 5067 | // Check for old temporal format if avoid_temporal_upgrade is disabled. | ||
| 5068 | 171 | mysql_mutex_lock(&LOCK_global_system_variables); | |
| 5069 | 171 | const bool check_temporal_upgrade = !avoid_temporal_upgrade; | |
| 5070 | 171 | mysql_mutex_unlock(&LOCK_global_system_variables); | |
| 5071 | |||
| 5072 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 171 times.
|
171 | if ((error = check_table_for_old_types(table, check_temporal_upgrade))) |
| 5073 | ✗ | return error; | |
| 5074 | 171 | error = ha_check_for_upgrade(check_opt); | |
| 5075 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 171 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
171 | if (error && (error != HA_ADMIN_NEEDS_CHECK)) return error; |
| 5076 |
3/4✓ Branch 0 taken 171 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 128 times.
✓ Branch 3 taken 43 times.
|
171 | if (!error && (check_opt->sql_flags & TT_FOR_UPGRADE)) return 0; |
| 5077 | } | ||
| 5078 | 2533 | return check(thd, check_opt); | |
| 5079 | } | ||
| 5080 | |||
| 5081 | /** | ||
| 5082 | A helper function to mark a transaction read-write, | ||
| 5083 | if it is started. | ||
| 5084 | */ | ||
| 5085 | |||
| 5086 | 176907964 | void handler::mark_trx_read_write() { | |
| 5087 | 176907964 | Ha_trx_info *ha_info = &ha_thd()->get_ha_data(ht->slot)->ha_info[0]; | |
| 5088 | /* | ||
| 5089 | When a storage engine method is called, the transaction must | ||
| 5090 | have been started, unless it's a DDL call, for which the | ||
| 5091 | storage engine starts the transaction internally, and commits | ||
| 5092 | it internally, without registering in the ha_list. | ||
| 5093 | Unfortunately here we can't know for sure if the engine | ||
| 5094 | has registered the transaction or not, so we must check. | ||
| 5095 | */ | ||
| 5096 |
2/2✓ Branch 0 taken 98116045 times.
✓ Branch 1 taken 78792842 times.
|
176909154 | if (ha_info->is_started()) { |
| 5097 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 98116045 times.
|
98116045 | assert(has_transactions()); |
| 5098 | /* | ||
| 5099 | table_share can be NULL in ha_delete_table(). See implementation | ||
| 5100 | of standalone function ha_delete_table() in sql_base.cc. | ||
| 5101 | */ | ||
| 5102 |
4/4✓ Branch 0 taken 98053646 times.
✓ Branch 1 taken 62399 times.
✓ Branch 2 taken 77673354 times.
✓ Branch 3 taken 20380292 times.
|
98116045 | if (table_share == nullptr || table_share->tmp_table == NO_TMP_TABLE) { |
| 5103 | /* TempTable and Heap tables don't use/support transactions. */ | ||
| 5104 | 77735753 | ha_info->set_trx_read_write(); | |
| 5105 | } | ||
| 5106 | } | ||
| 5107 | 176908951 | } | |
| 5108 | |||
| 5109 | /** | ||
| 5110 | Repair table: public interface. | ||
| 5111 | |||
| 5112 | @sa handler::repair() | ||
| 5113 | */ | ||
| 5114 | |||
| 5115 | 877 | int handler::ha_repair(THD *thd, HA_CHECK_OPT *check_opt) { | |
| 5116 | int result; | ||
| 5117 | 877 | mark_trx_read_write(); | |
| 5118 | |||
| 5119 | 877 | result = repair(thd, check_opt); | |
| 5120 |
3/4✓ Branch 0 taken 769 times.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 769 times.
|
877 | assert(result == HA_ADMIN_NOT_IMPLEMENTED || |
| 5121 | ha_table_flags() & HA_CAN_REPAIR); | ||
| 5122 | |||
| 5123 | // TODO: Check if table version in DD needs to be updated. | ||
| 5124 | // Previously we checked/updated FRM version here. | ||
| 5125 | 877 | return result; | |
| 5126 | } | ||
| 5127 | |||
| 5128 | /** | ||
| 5129 | Start bulk insert. | ||
| 5130 | |||
| 5131 | Allow the handler to optimize for multiple row insert. | ||
| 5132 | |||
| 5133 | @note rows == 0 means we will probably insert many rows. | ||
| 5134 | |||
| 5135 | @param rows Estimated rows to insert | ||
| 5136 | */ | ||
| 5137 | |||
| 5138 | 6254817 | void handler::ha_start_bulk_insert(ha_rows rows) { | |
| 5139 |
1/2✓ Branch 0 taken 6256200 times.
✗ Branch 1 not taken.
|
6254817 | DBUG_TRACE; |
| 5140 |
3/4✓ Branch 0 taken 6103918 times.
✓ Branch 1 taken 152282 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6103918 times.
|
6256200 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK); |
| 5141 | 6256200 | estimation_rows_to_insert = rows; | |
| 5142 |
1/2✓ Branch 0 taken 6255322 times.
✗ Branch 1 not taken.
|
6256200 | start_bulk_insert(rows); |
| 5143 | 6255322 | } | |
| 5144 | |||
| 5145 | /** | ||
| 5146 | End bulk insert. | ||
| 5147 | |||
| 5148 | @return Operation status | ||
| 5149 | @retval 0 Success | ||
| 5150 | @retval != 0 Failure (error code returned) | ||
| 5151 | */ | ||
| 5152 | |||
| 5153 | 6255915 | int handler::ha_end_bulk_insert() { | |
| 5154 |
1/2✓ Branch 0 taken 6256349 times.
✗ Branch 1 not taken.
|
6255915 | DBUG_TRACE; |
| 5155 |
3/4✓ Branch 0 taken 6104073 times.
✓ Branch 1 taken 152276 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6104073 times.
|
6256349 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK); |
| 5156 | 6256349 | estimation_rows_to_insert = 0; | |
| 5157 |
1/2✓ Branch 0 taken 6256217 times.
✗ Branch 1 not taken.
|
12512748 | return end_bulk_insert(); |
| 5158 | 6256217 | } | |
| 5159 | |||
| 5160 | /** | ||
| 5161 | Bulk update row: public interface. | ||
| 5162 | |||
| 5163 | @sa handler::bulk_update_row() | ||
| 5164 | */ | ||
| 5165 | |||
| 5166 | ✗ | int handler::ha_bulk_update_row(const uchar *old_data, uchar *new_data, | |
| 5167 | uint *dup_key_found) { | ||
| 5168 | ✗ | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK); | |
| 5169 | ✗ | mark_trx_read_write(); | |
| 5170 | |||
| 5171 | ✗ | return bulk_update_row(old_data, new_data, dup_key_found); | |
| 5172 | } | ||
| 5173 | |||
| 5174 | /** | ||
| 5175 | Delete all rows: public interface. | ||
| 5176 | |||
| 5177 | @sa handler::delete_all_rows() | ||
| 5178 | */ | ||
| 5179 | |||
| 5180 | 397011 | int handler::ha_delete_all_rows() { | |
| 5181 |
3/4✓ Branch 0 taken 3076 times.
✓ Branch 1 taken 393935 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3076 times.
|
397011 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK); |
| 5182 | 397011 | mark_trx_read_write(); | |
| 5183 | |||
| 5184 | 397011 | return delete_all_rows(); | |
| 5185 | } | ||
| 5186 | |||
| 5187 | /** | ||
| 5188 | Truncate table: public interface. | ||
| 5189 | |||
| 5190 | @sa handler::truncate() | ||
| 5191 | */ | ||
| 5192 | |||
| 5193 | 6008 | int handler::ha_truncate(dd::Table *table_def) { | |
| 5194 |
2/4✓ Branch 0 taken 6008 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6008 times.
|
6008 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK); |
| 5195 | 6008 | mark_trx_read_write(); | |
| 5196 | |||
| 5197 | 6008 | return truncate(table_def); | |
| 5198 | } | ||
| 5199 | |||
| 5200 | /** | ||
| 5201 | Optimize table: public interface. | ||
| 5202 | |||
| 5203 | @sa handler::optimize() | ||
| 5204 | */ | ||
| 5205 | |||
| 5206 | 2829 | int handler::ha_optimize(THD *thd, HA_CHECK_OPT *check_opt) { | |
| 5207 |
3/4✓ Branch 0 taken 2818 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2818 times.
|
2829 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK); |
| 5208 | 2829 | mark_trx_read_write(); | |
| 5209 | |||
| 5210 | 2829 | return optimize(thd, check_opt); | |
| 5211 | } | ||
| 5212 | |||
| 5213 | /** | ||
| 5214 | Analyze table: public interface. | ||
| 5215 | |||
| 5216 | @sa handler::analyze() | ||
| 5217 | */ | ||
| 5218 | |||
| 5219 | 14406 | int handler::ha_analyze(THD *thd, HA_CHECK_OPT *check_opt) { | |
| 5220 |
3/4✓ Branch 0 taken 14388 times.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14388 times.
|
14406 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 5221 | 14406 | mark_trx_read_write(); | |
| 5222 | |||
| 5223 | 14406 | return analyze(thd, check_opt); | |
| 5224 | } | ||
| 5225 | |||
| 5226 | /** | ||
| 5227 | Check and repair table: public interface. | ||
| 5228 | |||
| 5229 | @sa handler::check_and_repair() | ||
| 5230 | */ | ||
| 5231 | |||
| 5232 | 4 | bool handler::ha_check_and_repair(THD *thd) { | |
| 5233 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_UNLCK); |
| 5234 | 4 | mark_trx_read_write(); | |
| 5235 | |||
| 5236 | 4 | return check_and_repair(thd); | |
| 5237 | } | ||
| 5238 | |||
| 5239 | /** | ||
| 5240 | Disable indexes: public interface. | ||
| 5241 | |||
| 5242 | @sa handler::disable_indexes() | ||
| 5243 | */ | ||
| 5244 | |||
| 5245 | 727 | int handler::ha_disable_indexes(uint mode) { | |
| 5246 |
3/4✓ Branch 0 taken 691 times.
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 691 times.
|
727 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 5247 | 727 | mark_trx_read_write(); | |
| 5248 | |||
| 5249 | 727 | return disable_indexes(mode); | |
| 5250 | } | ||
| 5251 | |||
| 5252 | /** | ||
| 5253 | Enable indexes: public interface. | ||
| 5254 | |||
| 5255 | @sa handler::enable_indexes() | ||
| 5256 | */ | ||
| 5257 | |||
| 5258 | 701 | int handler::ha_enable_indexes(uint mode) { | |
| 5259 |
3/4✓ Branch 0 taken 685 times.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 685 times.
|
701 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 5260 | 701 | mark_trx_read_write(); | |
| 5261 | |||
| 5262 | 701 | return enable_indexes(mode); | |
| 5263 | } | ||
| 5264 | |||
| 5265 | /** | ||
| 5266 | Discard or import tablespace: public interface. | ||
| 5267 | |||
| 5268 | @sa handler::discard_or_import_tablespace() | ||
| 5269 | */ | ||
| 5270 | |||
| 5271 | 932 | int handler::ha_discard_or_import_tablespace(bool discard, | |
| 5272 | dd::Table *table_def) { | ||
| 5273 |
3/4✓ Branch 0 taken 916 times.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 916 times.
|
932 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK); |
| 5274 | 932 | mark_trx_read_write(); | |
| 5275 | |||
| 5276 | 932 | return discard_or_import_tablespace(discard, table_def); | |
| 5277 | } | ||
| 5278 | |||
| 5279 | 67979 | bool handler::ha_prepare_inplace_alter_table(TABLE *altered_table, | |
| 5280 | Alter_inplace_info *ha_alter_info, | ||
| 5281 | const dd::Table *old_table_def, | ||
| 5282 | dd::Table *new_table_def) { | ||
| 5283 |
3/4✓ Branch 0 taken 67949 times.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67949 times.
|
67979 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); |
| 5284 | 67979 | mark_trx_read_write(); | |
| 5285 | |||
| 5286 | 67979 | return prepare_inplace_alter_table(altered_table, ha_alter_info, | |
| 5287 | 67810 | old_table_def, new_table_def); | |
| 5288 | } | ||
| 5289 | |||
| 5290 | 67821 | bool handler::ha_commit_inplace_alter_table(TABLE *altered_table, | |
| 5291 | Alter_inplace_info *ha_alter_info, | ||
| 5292 | bool commit, | ||
| 5293 | const dd::Table *old_table_def, | ||
| 5294 | dd::Table *new_table_def) { | ||
| 5295 | /* | ||
| 5296 | At this point we should have an exclusive metadata lock on the table. | ||
| 5297 | The exception is if we're about to roll back changes (commit= false). | ||
| 5298 | In this case, we might be rolling back after a failed lock upgrade, | ||
| 5299 | so we could be holding the same lock level as for inplace_alter_table(). | ||
| 5300 | TABLE::mdl_ticket is 0 for temporary tables. | ||
| 5301 | */ | ||
| 5302 |
6/8✓ Branch 0 taken 29 times.
✓ Branch 1 taken 67792 times.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 562 times.
✓ Branch 5 taken 67230 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 562 times.
|
67821 | assert((table->s->tmp_table != NO_TMP_TABLE && !table->mdl_ticket) || |
| 5303 | (ha_thd()->mdl_context.owns_equal_or_stronger_lock( | ||
| 5304 | MDL_key::TABLE, table->s->db.str, table->s->table_name.str, | ||
| 5305 | MDL_EXCLUSIVE) || | ||
| 5306 | !commit)); | ||
| 5307 | |||
| 5308 | 67821 | return commit_inplace_alter_table(altered_table, ha_alter_info, commit, | |
| 5309 | 67702 | old_table_def, new_table_def); | |
| 5310 | } | ||
| 5311 | |||
| 5312 | /* | ||
| 5313 | Default implementation to support in-place/instant alter table | ||
| 5314 | for operations which do not affect table data. | ||
| 5315 | */ | ||
| 5316 | |||
| 5317 | 13965 | enum_alter_inplace_result handler::check_if_supported_inplace_alter( | |
| 5318 | TABLE *altered_table [[maybe_unused]], Alter_inplace_info *ha_alter_info) { | ||
| 5319 |
1/2✓ Branch 0 taken 13965 times.
✗ Branch 1 not taken.
|
13965 | DBUG_TRACE; |
| 5320 | |||
| 5321 | 13965 | HA_CREATE_INFO *create_info = ha_alter_info->create_info; | |
| 5322 | |||
| 5323 | 13965 | Alter_inplace_info::HA_ALTER_FLAGS inplace_offline_operations = | |
| 5324 | Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH | | ||
| 5325 | Alter_inplace_info::ALTER_COLUMN_NAME | | ||
| 5326 | Alter_inplace_info::ALTER_COLUMN_DEFAULT | | ||
| 5327 | Alter_inplace_info::CHANGE_CREATE_OPTION | | ||
| 5328 | Alter_inplace_info::ALTER_RENAME | Alter_inplace_info::RENAME_INDEX | | ||
| 5329 | Alter_inplace_info::ALTER_INDEX_COMMENT | | ||
| 5330 | Alter_inplace_info::CHANGE_INDEX_OPTION | | ||
| 5331 | Alter_inplace_info::ALTER_COLUMN_INDEX_LENGTH; | ||
| 5332 | |||
| 5333 | /* Is there at least one operation that requires copy algorithm? */ | ||
| 5334 |
2/2✓ Branch 0 taken 10953 times.
✓ Branch 1 taken 3012 times.
|
13965 | if (ha_alter_info->handler_flags & ~inplace_offline_operations) |
| 5335 | 10953 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 5336 | |||
| 5337 | /* | ||
| 5338 | ALTER TABLE tbl_name CONVERT TO CHARACTER SET .. and | ||
| 5339 | ALTER TABLE table_name DEFAULT CHARSET = .. most likely | ||
| 5340 | change column charsets and so not supported in-place through | ||
| 5341 | old API. | ||
| 5342 | |||
| 5343 | Changing of PACK_KEYS, MAX_ROWS and ROW_FORMAT options were | ||
| 5344 | not supported as in-place operations in old API either. | ||
| 5345 | */ | ||
| 5346 |
2/2✓ Branch 0 taken 2689 times.
✓ Branch 1 taken 323 times.
|
3012 | if (create_info->used_fields & |
| 5347 | (HA_CREATE_USED_CHARSET | HA_CREATE_USED_DEFAULT_CHARSET | | ||
| 5348 | 2689 | HA_CREATE_USED_PACK_KEYS | HA_CREATE_USED_MAX_ROWS) || | |
| 5349 |
2/2✓ Branch 0 taken 61 times.
✓ Branch 1 taken 2628 times.
|
2689 | (table->s->row_type != create_info->row_type)) |
| 5350 | 384 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 5351 | |||
| 5352 | // The presence of engine attributes does not prevent inplace so | ||
| 5353 | // that we get the same behavior as COMMENT. If SEs support engine | ||
| 5354 | // attribute values which are incompatible with INPLACE the need to | ||
| 5355 | // check for that when overriding (as they must do for parsed | ||
| 5356 | // comments). | ||
| 5357 | |||
| 5358 | 5256 | uint table_changes = (ha_alter_info->handler_flags & | |
| 5359 | Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH) | ||
| 5360 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 2605 times.
|
2628 | ? IS_EQUAL_PACK_LENGTH |
| 5361 | : IS_EQUAL_YES; | ||
| 5362 |
3/4✓ Branch 0 taken 2628 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2585 times.
✓ Branch 3 taken 43 times.
|
2628 | if (table->file->check_if_incompatible_data(create_info, table_changes) == |
| 5363 | COMPATIBLE_DATA_YES) | ||
| 5364 | 2585 | return HA_ALTER_INPLACE_INSTANT; | |
| 5365 | |||
| 5366 | 43 | return HA_ALTER_INPLACE_NOT_SUPPORTED; | |
| 5367 | 13965 | } | |
| 5368 | |||
| 5369 | 251 | void Alter_inplace_info::report_unsupported_error(const char *not_supported, | |
| 5370 | const char *try_instead) { | ||
| 5371 |
2/2✓ Branch 0 taken 98 times.
✓ Branch 1 taken 153 times.
|
251 | if (unsupported_reason == nullptr) |
| 5372 | 98 | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), not_supported, | |
| 5373 | try_instead); | ||
| 5374 | else | ||
| 5375 | 153 | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0), not_supported, | |
| 5376 | unsupported_reason, try_instead); | ||
| 5377 | 251 | } | |
| 5378 | |||
| 5379 | /** | ||
| 5380 | Rename table: public interface. | ||
| 5381 | |||
| 5382 | @sa handler::rename_table() | ||
| 5383 | */ | ||
| 5384 | |||
| 5385 | 40356 | int handler::ha_rename_table(const char *from, const char *to, | |
| 5386 | const dd::Table *from_table_def, | ||
| 5387 | dd::Table *to_table_def) { | ||
| 5388 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40356 times.
|
40356 | assert(m_lock_type == F_UNLCK); |
| 5389 | 40356 | mark_trx_read_write(); | |
| 5390 | |||
| 5391 | 40356 | return rename_table(from, to, from_table_def, to_table_def); | |
| 5392 | } | ||
| 5393 | |||
| 5394 | /** | ||
| 5395 | Delete table: public interface. | ||
| 5396 | |||
| 5397 | @sa handler::delete_table() | ||
| 5398 | */ | ||
| 5399 | |||
| 5400 | 218314 | int handler::ha_delete_table(const char *name, const dd::Table *table_def) { | |
| 5401 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 218314 times.
|
218314 | assert(m_lock_type == F_UNLCK); |
| 5402 | 218314 | mark_trx_read_write(); | |
| 5403 | |||
| 5404 | 218315 | return delete_table(name, table_def); | |
| 5405 | } | ||
| 5406 | |||
| 5407 | /** | ||
| 5408 | Drop table in the engine: public interface. | ||
| 5409 | |||
| 5410 | @sa handler::drop_table() | ||
| 5411 | */ | ||
| 5412 | |||
| 5413 | 599430 | void handler::ha_drop_table(const char *name) { | |
| 5414 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 599430 times.
|
599430 | assert(m_lock_type == F_UNLCK); |
| 5415 | 599430 | mark_trx_read_write(); | |
| 5416 | |||
| 5417 | 599430 | return drop_table(name); | |
| 5418 | } | ||
| 5419 | |||
| 5420 | /** | ||
| 5421 | Create a table in the engine: public interface. | ||
| 5422 | |||
| 5423 | @sa handler::create() | ||
| 5424 | */ | ||
| 5425 | |||
| 5426 | 329629 | int handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info, | |
| 5427 | dd::Table *table_def) { | ||
| 5428 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 329629 times.
|
329629 | assert(m_lock_type == F_UNLCK); |
| 5429 | 329629 | mark_trx_read_write(); | |
| 5430 | |||
| 5431 | 329629 | return create(name, form, info, table_def); | |
| 5432 | } | ||
| 5433 | |||
| 5434 | /** | ||
| 5435 | * Loads a table into its defined secondary storage engine: public interface. | ||
| 5436 | * This call may downgrade the table lock. Do not make any assumptions on the | ||
| 5437 | * MDL. | ||
| 5438 | * | ||
| 5439 | * @param table The table to load into the secondary engine. Its read_set tells | ||
| 5440 | * which columns to load. | ||
| 5441 | * | ||
| 5442 | * @sa handler::load_table() | ||
| 5443 | */ | ||
| 5444 | 87 | int handler::ha_load_table(const TABLE &table) { return load_table(table); } | |
| 5445 | |||
| 5446 | /** | ||
| 5447 | * Unloads a table from its defined secondary storage engine: public interface. | ||
| 5448 | * | ||
| 5449 | * @sa handler::unload_table() | ||
| 5450 | */ | ||
| 5451 | 112 | int handler::ha_unload_table(const char *db_name, const char *table_name, | |
| 5452 | bool error_if_not_loaded) { | ||
| 5453 | 112 | return unload_table(db_name, table_name, error_if_not_loaded); | |
| 5454 | } | ||
| 5455 | |||
| 5456 | /** | ||
| 5457 | Get the hard coded SE private data from the handler for a DD table. | ||
| 5458 | |||
| 5459 | @sa handler::get_se_private_data() | ||
| 5460 | */ | ||
| 5461 | 19008 | bool handler::ha_get_se_private_data(dd::Table *dd_table, bool reset) { | |
| 5462 | 19008 | return get_se_private_data(dd_table, reset); | |
| 5463 | } | ||
| 5464 | |||
| 5465 | /** | ||
| 5466 | Tell the storage engine that it is allowed to "disable transaction" in the | ||
| 5467 | handler. It is a hint that ACID is not required - it is used in NDB for | ||
| 5468 | ALTER TABLE, for example, when data are copied to temporary table. | ||
| 5469 | A storage engine may treat this hint any way it likes. NDB for example | ||
| 5470 | starts to commit every now and then automatically. | ||
| 5471 | This hint can be safely ignored. | ||
| 5472 | */ | ||
| 5473 | 25437 | int ha_enable_transaction(THD *thd, bool on) { | |
| 5474 | 25437 | int error = 0; | |
| 5475 |
1/2✓ Branch 0 taken 25440 times.
✗ Branch 1 not taken.
|
25437 | DBUG_TRACE; |
| 5476 |
3/8✓ Branch 0 taken 25436 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25440 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 25440 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
25440 | DBUG_PRINT("enter", ("on: %d", (int)on)); |
| 5477 | |||
| 5478 | #ifdef WITH_WSREP | ||
| 5479 |
2/2✓ Branch 0 taken 176 times.
✓ Branch 1 taken 25263 times.
|
25439 | if (thd->wsrep_applier) return 0; |
| 5480 | #endif /* WITH_WSREP */ | ||
| 5481 | |||
| 5482 |
2/2✓ Branch 0 taken 12629 times.
✓ Branch 1 taken 12635 times.
|
25263 | if ((thd->get_transaction()->m_flags.enabled = on)) { |
| 5483 | /* | ||
| 5484 | Now all storage engines should have transaction handling enabled. | ||
| 5485 | But some may have it enabled all the time - "disabling" transactions | ||
| 5486 | is an optimization hint that storage engine is free to ignore. | ||
| 5487 | So, let's commit an open transaction (if any) now. | ||
| 5488 | */ | ||
| 5489 |
2/4✓ Branch 0 taken 12628 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12628 times.
✗ Branch 3 not taken.
|
12629 | if (!(error = ha_commit_trans(thd, false))) |
| 5490 |
1/2✓ Branch 0 taken 12627 times.
✗ Branch 1 not taken.
|
12628 | error = trans_commit_implicit(thd); |
| 5491 | } | ||
| 5492 | 25262 | return error; | |
| 5493 | 25438 | } | |
| 5494 | |||
| 5495 | 488 | int handler::index_next_same(uchar *buf, const uchar *key, uint keylen) { | |
| 5496 | int error; | ||
| 5497 |
1/2✓ Branch 0 taken 488 times.
✗ Branch 1 not taken.
|
488 | DBUG_TRACE; |
| 5498 |
3/4✓ Branch 0 taken 488 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 349 times.
✓ Branch 3 taken 139 times.
|
488 | if (!(error = index_next(buf))) { |
| 5499 | 349 | ptrdiff_t ptrdiff = buf - table->record[0]; | |
| 5500 | 349 | uchar *save_record_0 = nullptr; | |
| 5501 | 349 | KEY *key_info = nullptr; | |
| 5502 | 349 | KEY_PART_INFO *key_part = nullptr; | |
| 5503 | 349 | KEY_PART_INFO *key_part_end = nullptr; | |
| 5504 | |||
| 5505 | /* | ||
| 5506 | key_cmp_if_same() compares table->record[0] against 'key'. | ||
| 5507 | In parts it uses table->record[0] directly, in parts it uses | ||
| 5508 | field objects with their local pointers into table->record[0]. | ||
| 5509 | If 'buf' is distinct from table->record[0], we need to move | ||
| 5510 | all record references. This is table->record[0] itself and | ||
| 5511 | the field pointers of the fields used in this key. | ||
| 5512 | */ | ||
| 5513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 349 times.
|
349 | if (ptrdiff) { |
| 5514 | ✗ | save_record_0 = table->record[0]; | |
| 5515 | ✗ | table->record[0] = buf; | |
| 5516 | ✗ | key_info = table->key_info + active_index; | |
| 5517 | ✗ | key_part = key_info->key_part; | |
| 5518 | ✗ | key_part_end = key_part + key_info->user_defined_key_parts; | |
| 5519 | ✗ | for (; key_part < key_part_end; key_part++) { | |
| 5520 | ✗ | assert(key_part->field); | |
| 5521 | ✗ | key_part->field->move_field_offset(ptrdiff); | |
| 5522 | } | ||
| 5523 | } | ||
| 5524 | |||
| 5525 |
3/4✓ Branch 0 taken 349 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 324 times.
|
349 | if (key_cmp_if_same(table, key, active_index, keylen)) |
| 5526 | 25 | error = HA_ERR_END_OF_FILE; | |
| 5527 | |||
| 5528 | /* Move back if necessary. */ | ||
| 5529 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 349 times.
|
349 | if (ptrdiff) { |
| 5530 | ✗ | table->record[0] = save_record_0; | |
| 5531 | ✗ | for (key_part = key_info->key_part; key_part < key_part_end; key_part++) | |
| 5532 | ✗ | key_part->field->move_field_offset(-ptrdiff); | |
| 5533 | } | ||
| 5534 | } | ||
| 5535 | 488 | return error; | |
| 5536 | 488 | } | |
| 5537 | |||
| 5538 | // Updates the global table stats with the TABLE this handler represents. | ||
| 5539 | 47561 | void handler::update_global_table_stats() { | |
| 5540 |
4/4✓ Branch 0 taken 41381 times.
✓ Branch 1 taken 6180 times.
✓ Branch 2 taken 30375 times.
✓ Branch 3 taken 11006 times.
|
47561 | if (!rows_read && !rows_changed) return; // Nothing to update. |
| 5541 | // table_cache_key is db_name + '\0' + table_name + '\0'. | ||
| 5542 |
3/6✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17186 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 17186 times.
|
17186 | if (!table->s || !table->s->table_cache_key.str || !table->s->table_name.str) |
| 5543 | ✗ | return; | |
| 5544 | |||
| 5545 | // [db] + '.' + [table] | ||
| 5546 |
1/2✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
|
17186 | std::string key{table->s->table_cache_key.str}; |
| 5547 |
1/2✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
|
17186 | key.append(1, '.'); |
| 5548 |
1/2✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
|
17186 | key.append(table->s->table_name.str); |
| 5549 | 17186 | key.shrink_to_fit(); | |
| 5550 | |||
| 5551 | 17186 | const ulonglong rows_changed_x_indexes = | |
| 5552 |
2/2✓ Branch 0 taken 17107 times.
✓ Branch 1 taken 79 times.
|
17186 | rows_changed * (table->s->keys ? table->s->keys : 1); |
| 5553 | |||
| 5554 |
1/2✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
|
17186 | mysql_mutex_lock(&LOCK_global_table_stats); |
| 5555 | // Gets the global table stats, creating one if necessary. | ||
| 5556 |
1/2✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
|
17186 | const auto &it = global_table_stats->find(key); |
| 5557 |
2/2✓ Branch 0 taken 289 times.
✓ Branch 1 taken 16897 times.
|
17186 | if (it == global_table_stats->cend()) { |
| 5558 |
1/2✓ Branch 0 taken 289 times.
✗ Branch 1 not taken.
|
289 | global_table_stats->emplace( |
| 5559 | 289 | std::piecewise_construct, std::forward_as_tuple(key), | |
| 5560 | 289 | std::forward_as_tuple(static_cast<int>(ht->db_type), rows_read, | |
| 5561 | 289 | rows_changed, rows_changed_x_indexes)); | |
| 5562 | } else { | ||
| 5563 | 16897 | TABLE_STATS *const table_stats = &it->second; | |
| 5564 | 16897 | table_stats->rows_read += rows_read; | |
| 5565 | 16897 | table_stats->rows_changed += rows_changed; | |
| 5566 | 16897 | table_stats->rows_changed_x_indexes += rows_changed_x_indexes; | |
| 5567 | } | ||
| 5568 |
1/2✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
|
17186 | mysql_mutex_unlock(&LOCK_global_table_stats); |
| 5569 |
1/2✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
|
17186 | ha_thd()->diff_total_read_rows += rows_read; |
| 5570 | 17186 | rows_read = rows_changed = 0; | |
| 5571 | 17186 | } | |
| 5572 | |||
| 5573 | // Updates the global index stats with this handler's accumulated index reads. | ||
| 5574 | 47561 | void handler::update_global_index_stats() { | |
| 5575 | // table_cache_key is db_name + '\0' + table_name + '\0'. | ||
| 5576 |
3/6✓ Branch 0 taken 47561 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47561 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 47561 times.
✗ Branch 5 not taken.
|
47561 | if (!table || !table->s || !table->s->table_cache_key.str || |
| 5577 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47561 times.
|
47561 | !table->s->table_name.str) |
| 5578 | ✗ | return; | |
| 5579 | |||
| 5580 |
2/2✓ Branch 0 taken 161314 times.
✓ Branch 1 taken 47561 times.
|
208875 | for (uint x = 0; x < table->s->keys; ++x) { |
| 5581 |
2/2✓ Branch 0 taken 7499 times.
✓ Branch 1 taken 153815 times.
|
161314 | if (index_rows_read[x]) { |
| 5582 | // Rows were read using this index. | ||
| 5583 | 7499 | KEY *key_info = &table->key_info[x]; | |
| 5584 | |||
| 5585 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7499 times.
|
7499 | if (!key_info->name) continue; |
| 5586 | |||
| 5587 | // [db] + '.' + [table] + '.' + [index] | ||
| 5588 |
1/2✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
|
7499 | std::string key{table->s->table_cache_key.str}; |
| 5589 |
1/2✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
|
7499 | key.append(1, '.'); |
| 5590 |
1/2✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
|
7499 | key.append(table->s->table_name.str); |
| 5591 |
1/2✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
|
7499 | key.append(1, '.'); |
| 5592 |
1/2✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
|
7499 | key.append(key_info->name); |
| 5593 | 7499 | key.shrink_to_fit(); | |
| 5594 | |||
| 5595 |
1/2✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
|
7499 | mysql_mutex_lock(&LOCK_global_index_stats); |
| 5596 |
1/2✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
|
7499 | const auto &it = global_index_stats->find(key); |
| 5597 |
2/2✓ Branch 0 taken 308 times.
✓ Branch 1 taken 7191 times.
|
7499 | if (it == global_index_stats->cend()) { |
| 5598 |
1/2✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
|
308 | global_index_stats->emplace(key, index_rows_read[x]); |
| 5599 | } else { | ||
| 5600 | 7191 | it->second += index_rows_read[x]; | |
| 5601 | } | ||
| 5602 |
1/2✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
|
7499 | mysql_mutex_unlock(&LOCK_global_index_stats); |
| 5603 | 7499 | index_rows_read[x] = 0; | |
| 5604 | 7499 | } | |
| 5605 | } | ||
| 5606 | } | ||
| 5607 | |||
| 5608 | /**************************************************************************** | ||
| 5609 | ** Some general functions that isn't in the handler class | ||
| 5610 | ****************************************************************************/ | ||
| 5611 | |||
| 5612 | /** | ||
| 5613 | Initiates table-file and calls appropriate database-creator. | ||
| 5614 | |||
| 5615 | @param thd Thread context. | ||
| 5616 | @param path Path to table file (without extension). | ||
| 5617 | @param db Database name. | ||
| 5618 | @param table_name Table name. | ||
| 5619 | @param create_info HA_CREATE_INFO describing table. | ||
| 5620 | @param update_create_info Indicates that create_info needs to be | ||
| 5621 | updated from table share. | ||
| 5622 | @param is_temp_table Indicates that this is temporary table (for | ||
| 5623 | cases when this info is not available from | ||
| 5624 | HA_CREATE_INFO). | ||
| 5625 | @param table_def Data-dictionary object describing table to | ||
| 5626 | be used for table creation. Can be adjusted | ||
| 5627 | by storage engine if it supports atomic DDL. | ||
| 5628 | For non-temporary tables these changes will | ||
| 5629 | be saved to the data-dictionary by this call. | ||
| 5630 | |||
| 5631 | @retval | ||
| 5632 | 0 ok | ||
| 5633 | @retval | ||
| 5634 | 1 error | ||
| 5635 | */ | ||
| 5636 | 329876 | int ha_create_table(THD *thd, const char *path, const char *db, | |
| 5637 | const char *table_name, HA_CREATE_INFO *create_info, | ||
| 5638 | const List<Create_field> *create_fields, | ||
| 5639 | bool update_create_info, bool is_temp_table, | ||
| 5640 | dd::Table *table_def) { | ||
| 5641 | 329876 | int error = 1; | |
| 5642 |
1/2✓ Branch 0 taken 329879 times.
✗ Branch 1 not taken.
|
329876 | TABLE table; |
| 5643 | char name_buff[FN_REFLEN]; | ||
| 5644 | const char *name; | ||
| 5645 |
1/2✓ Branch 0 taken 329878 times.
✗ Branch 1 not taken.
|
329879 | TABLE_SHARE share; |
| 5646 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 5647 | 638969 | bool temp_table = is_temp_table || | |
| 5648 |
4/4✓ Branch 0 taken 309091 times.
✓ Branch 1 taken 20787 times.
✓ Branch 2 taken 261588 times.
✓ Branch 3 taken 47503 times.
|
591466 | (create_info->options & HA_LEX_CREATE_TMP_TABLE) || |
| 5649 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 261588 times.
|
261588 | (strstr(path, tmp_file_prefix) != nullptr); |
| 5650 | #endif | ||
| 5651 |
1/2✓ Branch 0 taken 329880 times.
✗ Branch 1 not taken.
|
329878 | DBUG_TRACE; |
| 5652 | |||
| 5653 |
1/2✓ Branch 0 taken 329879 times.
✗ Branch 1 not taken.
|
329880 | init_tmp_table_share(thd, &share, db, 0, table_name, path, nullptr); |
| 5654 | |||
| 5655 |
3/4✓ Branch 0 taken 329880 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 329878 times.
|
329879 | if (open_table_def(thd, &share, *table_def)) goto err; |
| 5656 | |||
| 5657 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 5658 |
1/2✓ Branch 0 taken 329877 times.
✗ Branch 1 not taken.
|
329878 | share.m_psi = PSI_TABLE_CALL(get_table_share)(temp_table, &share); |
| 5659 | #endif | ||
| 5660 | |||
| 5661 | // When db_stat is 0, we can pass nullptr as dd::Table since it won't be used. | ||
| 5662 | 329877 | destroy(&table); | |
| 5663 |
3/4✓ Branch 0 taken 329878 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 249 times.
✓ Branch 3 taken 329629 times.
|
329877 | if (open_table_from_share(thd, &share, "", 0, (uint)READ_ALL, 0, &table, true, |
| 5664 | nullptr)) { | ||
| 5665 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 5666 | PSI_TABLE_CALL(drop_table_share) | ||
| 5667 |
1/2✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
|
249 | (temp_table, db, strlen(db), table_name, strlen(table_name)); |
| 5668 | #endif | ||
| 5669 | 249 | goto err; | |
| 5670 | } | ||
| 5671 | |||
| 5672 |
3/4✓ Branch 0 taken 50747 times.
✓ Branch 1 taken 278882 times.
✓ Branch 2 taken 50747 times.
✗ Branch 3 not taken.
|
329629 | if (update_create_info) update_create_info_from_table(create_info, &table); |
| 5673 | |||
| 5674 | /* | ||
| 5675 | Updating field definitions in 'table' with zip_dict_name values | ||
| 5676 | from 'create_fields' | ||
| 5677 | */ | ||
| 5678 |
2/2✓ Branch 0 taken 278882 times.
✓ Branch 1 taken 50747 times.
|
329629 | if (create_fields != nullptr) { |
| 5679 |
1/2✓ Branch 0 taken 278882 times.
✗ Branch 1 not taken.
|
278882 | table.update_compressed_columns_info(*create_fields); |
| 5680 | } | ||
| 5681 | |||
| 5682 |
1/2✓ Branch 0 taken 329629 times.
✗ Branch 1 not taken.
|
329629 | name = get_canonical_filename(table.file, share.path.str, name_buff); |
| 5683 | |||
| 5684 |
1/2✓ Branch 0 taken 329570 times.
✗ Branch 1 not taken.
|
329629 | error = table.file->ha_create(name, &table, create_info, table_def); |
| 5685 | |||
| 5686 |
2/2✓ Branch 0 taken 413 times.
✓ Branch 1 taken 329157 times.
|
329570 | if (error) { |
| 5687 |
1/2✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
|
413 | table.file->print_error(error, MYF(0)); |
| 5688 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 5689 | PSI_TABLE_CALL(drop_table_share) | ||
| 5690 |
1/2✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
|
413 | (temp_table, db, strlen(db), table_name, strlen(table_name)); |
| 5691 | #endif | ||
| 5692 | } else { | ||
| 5693 | /* | ||
| 5694 | We do post-create update only for engines supporting atomic DDL | ||
| 5695 | as only such engines are allowed to update dd::Table objects in | ||
| 5696 | handler::ha_create(). | ||
| 5697 | The dd::Table objects for temporary tables are not stored in DD | ||
| 5698 | so do not need DD update. | ||
| 5699 | The dd::Table objects representing the DD tables themselves cannot | ||
| 5700 | be stored until the DD tables have been created in the SE. | ||
| 5701 | */ | ||
| 5702 |
2/2✓ Branch 0 taken 261018 times.
✓ Branch 1 taken 19556 times.
|
280574 | if (!((create_info->options & HA_LEX_CREATE_TMP_TABLE) || is_temp_table || |
| 5703 |
14/22✓ Branch 0 taken 280574 times.
✓ Branch 1 taken 48583 times.
✓ Branch 2 taken 261018 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 261018 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 261018 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 261018 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 251396 times.
✓ Branch 11 taken 9622 times.
✓ Branch 12 taken 261018 times.
✓ Branch 13 taken 68139 times.
✓ Branch 14 taken 261018 times.
✓ Branch 15 taken 68139 times.
✓ Branch 16 taken 146971 times.
✓ Branch 17 taken 182186 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
|
861127 | dd::get_dictionary()->is_dd_table_name(db, table_name)) && |
| 5704 |
2/2✓ Branch 0 taken 146971 times.
✓ Branch 1 taken 104425 times.
|
251396 | (table.file->ht->flags & HTON_SUPPORTS_ATOMIC_DDL)) { |
| 5705 |
3/4✓ Branch 0 taken 146971 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 146970 times.
|
146971 | if (thd->dd_client()->update<dd::Table>(table_def)) error = 1; |
| 5706 | } | ||
| 5707 | } | ||
| 5708 |
1/2✓ Branch 0 taken 329570 times.
✗ Branch 1 not taken.
|
329570 | (void)closefrm(&table, false); |
| 5709 | 329821 | err: | |
| 5710 |
1/2✓ Branch 0 taken 329821 times.
✗ Branch 1 not taken.
|
329821 | free_table_share(&share); |
| 5711 | 329821 | return error != 0; | |
| 5712 | 329821 | } | |
| 5713 | |||
| 5714 | /** | ||
| 5715 | Try to discover table from engine. | ||
| 5716 | |||
| 5717 | @note | ||
| 5718 | If found, import the serialized dictionary information. | ||
| 5719 | |||
| 5720 | @retval | ||
| 5721 | -1 Table did not exists | ||
| 5722 | @retval | ||
| 5723 | 0 Table created ok | ||
| 5724 | @retval | ||
| 5725 | > 0 Error, table existed but could not be created | ||
| 5726 | */ | ||
| 5727 | 14340 | int ha_create_table_from_engine(THD *thd, const char *db, const char *name) { | |
| 5728 | int error; | ||
| 5729 | uchar *sdi_blob; | ||
| 5730 | size_t sdi_len; | ||
| 5731 |
1/2✓ Branch 0 taken 14340 times.
✗ Branch 1 not taken.
|
14340 | DBUG_TRACE; |
| 5732 |
3/8✓ Branch 0 taken 14340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14340 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14340 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
14340 | DBUG_PRINT("enter", ("name '%s'.'%s'", db, name)); |
| 5733 | |||
| 5734 |
2/4✓ Branch 0 taken 14340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14340 times.
✗ Branch 3 not taken.
|
14340 | if ((error = ha_discover(thd, db, name, &sdi_blob, &sdi_len))) { |
| 5735 | /* Table could not be discovered and thus not created */ | ||
| 5736 | 14340 | return error; | |
| 5737 | } | ||
| 5738 | |||
| 5739 | /* | ||
| 5740 | Table was successfully discovered from SE, check if SDI need | ||
| 5741 | to be installed or if that has already been done by SE. | ||
| 5742 | No SDI blob returned from SE indicates it has installed | ||
| 5743 | the table definition for this table into DD itself. | ||
| 5744 | Otherwise, import the SDI based on the sdi_blob and sdi_len, | ||
| 5745 | which are set. | ||
| 5746 | */ | ||
| 5747 | ✗ | if (sdi_blob) { | |
| 5748 | ✗ | error = import_serialized_meta_data(sdi_blob, sdi_len, true); | |
| 5749 | ✗ | my_free(sdi_blob); | |
| 5750 | ✗ | if (error) return 2; | |
| 5751 | } | ||
| 5752 | |||
| 5753 | ✗ | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); | |
| 5754 | ✗ | const dd::Table *table_def = nullptr; | |
| 5755 | ✗ | if (thd->dd_client()->acquire(db, name, &table_def)) return 3; | |
| 5756 | |||
| 5757 | ✗ | if (table_def == nullptr) { | |
| 5758 | ✗ | my_error(ER_NO_SUCH_TABLE, MYF(0), db, name); | |
| 5759 | ✗ | return 3; | |
| 5760 | } | ||
| 5761 | |||
| 5762 | char path[FN_REFLEN + 1]; | ||
| 5763 | ✗ | build_table_filename(path, sizeof(path) - 1, db, name, "", 0); | |
| 5764 | |||
| 5765 | ✗ | TABLE_SHARE share; | |
| 5766 | ✗ | init_tmp_table_share(thd, &share, db, 0, name, path, nullptr); | |
| 5767 | |||
| 5768 | ✗ | if (open_table_def(thd, &share, *table_def)) return 3; | |
| 5769 | |||
| 5770 | ✗ | TABLE table; | |
| 5771 | // When db_stat is 0, we can pass nullptr as dd::Table since it won't be used. | ||
| 5772 | ✗ | if (open_table_from_share(thd, &share, "", 0, 0, 0, &table, false, nullptr)) { | |
| 5773 | ✗ | free_table_share(&share); | |
| 5774 | ✗ | return 3; | |
| 5775 | } | ||
| 5776 | |||
| 5777 | ✗ | HA_CREATE_INFO create_info; | |
| 5778 | ✗ | update_create_info_from_table(&create_info, &table); | |
| 5779 | ✗ | create_info.table_options |= HA_OPTION_CREATE_FROM_ENGINE; | |
| 5780 | |||
| 5781 | ✗ | get_canonical_filename(table.file, path, path); | |
| 5782 | ✗ | std::unique_ptr<dd::Table> table_def_clone(table_def->clone()); | |
| 5783 | error = | ||
| 5784 | ✗ | table.file->ha_create(path, &table, &create_info, table_def_clone.get()); | |
| 5785 | /* | ||
| 5786 | Note that the table_def_clone is not stored into the DD, | ||
| 5787 | necessary changes to the table_def should already have | ||
| 5788 | been done in ha_discover/import_serialized_meta_data. | ||
| 5789 | */ | ||
| 5790 | ✗ | (void)closefrm(&table, true); | |
| 5791 | |||
| 5792 | ✗ | return error != 0; | |
| 5793 | 14340 | } | |
| 5794 | |||
| 5795 | /** | ||
| 5796 | Try to find a table in a storage engine. | ||
| 5797 | |||
| 5798 | @param thd Thread handle | ||
| 5799 | @param db Normalized table schema name | ||
| 5800 | @param name Normalized table name. | ||
| 5801 | @param[out] exists Only valid if the function succeeded. | ||
| 5802 | |||
| 5803 | @retval true An error is found | ||
| 5804 | @retval false Success, check *exists | ||
| 5805 | */ | ||
| 5806 | |||
| 5807 | 583713 | bool ha_check_if_table_exists(THD *thd, const char *db, const char *name, | |
| 5808 | bool *exists) { | ||
| 5809 | 583713 | uchar *frmblob = nullptr; | |
| 5810 | size_t frmlen; | ||
| 5811 |
1/2✓ Branch 0 taken 583715 times.
✗ Branch 1 not taken.
|
583713 | DBUG_TRACE; |
| 5812 | |||
| 5813 |
1/2✓ Branch 0 taken 583715 times.
✗ Branch 1 not taken.
|
583715 | *exists = !ha_discover(thd, db, name, &frmblob, &frmlen); |
| 5814 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 583715 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
583715 | if (*exists) my_free(frmblob); |
| 5815 | |||
| 5816 | 583715 | return false; | |
| 5817 | 583715 | } | |
| 5818 | |||
| 5819 | /** | ||
| 5820 | Check if a table specified by name is a system table. | ||
| 5821 | |||
| 5822 | @param db Database name for the table. | ||
| 5823 | @param table_name Table name to be checked. | ||
| 5824 | @param[out] is_sql_layer_system_table True if a system table belongs to | ||
| 5825 | sql_layer. | ||
| 5826 | |||
| 5827 | @return Operation status | ||
| 5828 | @retval true If the table name is a system table. | ||
| 5829 | @retval false If the table name is a user-level table. | ||
| 5830 | */ | ||
| 5831 | |||
| 5832 | 496839 | static bool check_if_system_table(const char *db, const char *table_name, | |
| 5833 | bool *is_sql_layer_system_table) { | ||
| 5834 | // Check if we have the system database name in the command. | ||
| 5835 |
4/6✓ Branch 0 taken 496843 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 496843 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 118066 times.
✓ Branch 5 taken 378777 times.
|
496839 | if (!dd::get_dictionary()->is_dd_schema_name(db)) return false; |
| 5836 | |||
| 5837 | // Check if this is SQL layer system tables. | ||
| 5838 |
5/8✓ Branch 0 taken 378777 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 378777 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 378777 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 45518 times.
✓ Branch 7 taken 333259 times.
|
378777 | if (dd::get_dictionary()->is_system_table_name(db, table_name)) |
| 5839 | 45518 | *is_sql_layer_system_table = true; | |
| 5840 | |||
| 5841 | 378777 | return true; | |
| 5842 | } | ||
| 5843 | |||
| 5844 | /** | ||
| 5845 | @brief Check if a given table is a system table. | ||
| 5846 | |||
| 5847 | @details The primary purpose of introducing this function is to stop system | ||
| 5848 | tables to be created or being moved to undesired storage engines. | ||
| 5849 | |||
| 5850 | @todo There is another function called is_system_table_name() used by | ||
| 5851 | get_table_category(), which is used to set TABLE_SHARE table_category. | ||
| 5852 | It checks only a subset of table name like proc, event and time*. | ||
| 5853 | We cannot use below function in get_table_category(), | ||
| 5854 | as that affects locking mechanism. If we need to | ||
| 5855 | unify these functions, we need to fix locking issues generated. | ||
| 5856 | |||
| 5857 | @param hton Handlerton of new engine. | ||
| 5858 | @param db Database name. | ||
| 5859 | @param table_name Table name to be checked. | ||
| 5860 | |||
| 5861 | @return Operation status | ||
| 5862 | @retval true If the table name is a valid system table | ||
| 5863 | or if its a valid user table. | ||
| 5864 | |||
| 5865 | @retval false If the table name is a system table name | ||
| 5866 | and does not belong to engine specified | ||
| 5867 | in the command. | ||
| 5868 | */ | ||
| 5869 | |||
| 5870 | 496839 | bool ha_check_if_supported_system_table(handlerton *hton, const char *db, | |
| 5871 | const char *table_name) { | ||
| 5872 |
1/2✓ Branch 0 taken 496842 times.
✗ Branch 1 not taken.
|
496839 | DBUG_TRACE; |
| 5873 | st_sys_tbl_chk_params check_params; | ||
| 5874 | |||
| 5875 | 496842 | check_params.is_sql_layer_system_table = false; | |
| 5876 |
3/4✓ Branch 0 taken 496842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118065 times.
✓ Branch 3 taken 378777 times.
|
496842 | if (!check_if_system_table(db, table_name, |
| 5877 | &check_params.is_sql_layer_system_table)) | ||
| 5878 | 118065 | return true; // It's a user table name | |
| 5879 | |||
| 5880 | // Check if this is a system table and if some engine supports it. | ||
| 5881 | 757554 | check_params.status = check_params.is_sql_layer_system_table | |
| 5882 |
2/2✓ Branch 0 taken 45518 times.
✓ Branch 1 taken 333259 times.
|
378777 | ? st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE |
| 5883 | : st_sys_tbl_chk_params::NOT_KNOWN_SYSTEM_TABLE; | ||
| 5884 | 378777 | check_params.db_type = hton->db_type; | |
| 5885 | 378777 | check_params.table_name = table_name; | |
| 5886 | 378777 | check_params.db = db; | |
| 5887 |
1/2✓ Branch 0 taken 378777 times.
✗ Branch 1 not taken.
|
378777 | plugin_foreach(nullptr, check_engine_system_table_handlerton, |
| 5888 | MYSQL_STORAGE_ENGINE_PLUGIN, &check_params); | ||
| 5889 | |||
| 5890 | // SE does not support this system table. | ||
| 5891 |
2/2✓ Branch 0 taken 122 times.
✓ Branch 1 taken 378655 times.
|
378777 | if (check_params.status == st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE) |
| 5892 | 122 | return false; | |
| 5893 | |||
| 5894 | // It's a system table or a valid user table. | ||
| 5895 | 378655 | return true; | |
| 5896 | 496842 | } | |
| 5897 | |||
| 5898 | /** | ||
| 5899 | @brief Called for each SE to check if given db, tablename is a system table. | ||
| 5900 | |||
| 5901 | @details The primary purpose of introducing this function is to stop system | ||
| 5902 | tables to be created or being moved to undesired storage engines. | ||
| 5903 | |||
| 5904 | @param plugin Points to specific SE. | ||
| 5905 | @param arg Is of type struct st_sys_tbl_chk_params. | ||
| 5906 | |||
| 5907 | @note | ||
| 5908 | args->status Indicates OUT param, | ||
| 5909 | see struct st_sys_tbl_chk_params definition for more info. | ||
| 5910 | |||
| 5911 | @return Operation status | ||
| 5912 | @retval true There was a match found. | ||
| 5913 | This will stop doing checks with other SE's. | ||
| 5914 | |||
| 5915 | @retval false There was no match found. | ||
| 5916 | Other SE's will be checked to find a match. | ||
| 5917 | */ | ||
| 5918 | 1118251 | static bool check_engine_system_table_handlerton(THD *, plugin_ref plugin, | |
| 5919 | void *arg) { | ||
| 5920 | 1118251 | st_sys_tbl_chk_params *check_params = (st_sys_tbl_chk_params *)arg; | |
| 5921 | 1118251 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 5922 | |||
| 5923 | // Do we already know that the table is a system table? | ||
| 5924 |
2/2✓ Branch 0 taken 80298 times.
✓ Branch 1 taken 1037953 times.
|
1118251 | if (check_params->status == st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE) { |
| 5925 | /* | ||
| 5926 | If this is the same SE specified in the command, we can | ||
| 5927 | simply ask the SE if it supports it stop the search regardless. | ||
| 5928 | */ | ||
| 5929 |
2/2✓ Branch 0 taken 45518 times.
✓ Branch 1 taken 34780 times.
|
80298 | if (hton->db_type == check_params->db_type) { |
| 5930 |
4/4✓ Branch 0 taken 45474 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 45396 times.
✓ Branch 3 taken 122 times.
|
90992 | if (hton->is_supported_system_table && |
| 5931 |
2/2✓ Branch 0 taken 45396 times.
✓ Branch 1 taken 78 times.
|
45474 | hton->is_supported_system_table( |
| 5932 | check_params->db, check_params->table_name, | ||
| 5933 | 45474 | check_params->is_sql_layer_system_table)) | |
| 5934 | 45396 | check_params->status = st_sys_tbl_chk_params::SUPPORTED_SYSTEM_TABLE; | |
| 5935 | 45518 | return true; | |
| 5936 | } | ||
| 5937 | /* | ||
| 5938 | If this is a different SE, there is no point in asking the SE | ||
| 5939 | since we already know it's a system table and we don't care | ||
| 5940 | if it is supported or not. | ||
| 5941 | */ | ||
| 5942 | 34780 | return false; | |
| 5943 | } | ||
| 5944 | |||
| 5945 | /* | ||
| 5946 | We don't yet know if the table is a system table or not. | ||
| 5947 | We therefore must always ask the SE. | ||
| 5948 | */ | ||
| 5949 |
3/4✓ Branch 0 taken 999777 times.
✓ Branch 1 taken 38176 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1037953 times.
|
2037730 | if (hton->is_supported_system_table && |
| 5950 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 999777 times.
|
999777 | hton->is_supported_system_table( |
| 5951 | check_params->db, check_params->table_name, | ||
| 5952 | 999777 | check_params->is_sql_layer_system_table)) { | |
| 5953 | /* | ||
| 5954 | If this is the same SE specified in the command, we know it's a | ||
| 5955 | supported system table and can stop the search. | ||
| 5956 | */ | ||
| 5957 | ✗ | if (hton->db_type == check_params->db_type) { | |
| 5958 | ✗ | check_params->status = st_sys_tbl_chk_params::SUPPORTED_SYSTEM_TABLE; | |
| 5959 | ✗ | return true; | |
| 5960 | } else | ||
| 5961 | ✗ | check_params->status = st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE; | |
| 5962 | } | ||
| 5963 | |||
| 5964 | 1037953 | return false; | |
| 5965 | } | ||
| 5966 | |||
| 5967 | 103615 | static bool rm_tmp_tables_handlerton(THD *thd, plugin_ref plugin, void *files) { | |
| 5968 | 103615 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 5969 | |||
| 5970 |
5/6✓ Branch 0 taken 103364 times.
✓ Branch 1 taken 251 times.
✓ Branch 2 taken 37671 times.
✓ Branch 3 taken 65693 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 103615 times.
|
141286 | if (hton->state == SHOW_OPTION_YES && hton->rm_tmp_tables && |
| 5971 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37671 times.
|
37671 | hton->rm_tmp_tables(hton, thd, (List<LEX_STRING> *)files)) |
| 5972 | ✗ | return true; | |
| 5973 | |||
| 5974 | 103615 | return false; | |
| 5975 | } | ||
| 5976 | |||
| 5977 | /** | ||
| 5978 | Ask all SEs to drop all temporary tables which have been left from | ||
| 5979 | previous server run. Used on server start-up. | ||
| 5980 | |||
| 5981 | @param[in] thd Thread context. | ||
| 5982 | @param[in,out] files List of files in directories for temporary files | ||
| 5983 | which match tmp_file_prefix and thus can belong to | ||
| 5984 | temporary tables. If any SE recognizes some file as | ||
| 5985 | belonging to temporary table in this SE and deletes | ||
| 5986 | the file it is also supposed to remove file from | ||
| 5987 | this list. | ||
| 5988 | */ | ||
| 5989 | |||
| 5990 | 9418 | bool ha_rm_tmp_tables(THD *thd, List<LEX_STRING> *files) { | |
| 5991 | 9418 | return plugin_foreach(thd, rm_tmp_tables_handlerton, | |
| 5992 | MYSQL_STORAGE_ENGINE_PLUGIN, files); | ||
| 5993 | } | ||
| 5994 | |||
| 5995 | /** | ||
| 5996 | Default implementation for handlerton::rm_tmp_tables() method which | ||
| 5997 | simply removes all files from "files" list which have one of SE's | ||
| 5998 | extensions. This implementation corresponds to default implementation | ||
| 5999 | of handler::delete_table() method. | ||
| 6000 | */ | ||
| 6001 | |||
| 6002 | 37671 | bool default_rm_tmp_tables(handlerton *hton, THD *, List<LEX_STRING> *files) { | |
| 6003 |
1/2✓ Branch 0 taken 37671 times.
✗ Branch 1 not taken.
|
37671 | List_iterator<LEX_STRING> files_it(*files); |
| 6004 | LEX_STRING *file_path; | ||
| 6005 | |||
| 6006 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37671 times.
|
37671 | if (!hton->file_extensions) return false; |
| 6007 | |||
| 6008 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 37671 times.
|
37717 | while ((file_path = files_it++)) { |
| 6009 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | const char *file_ext = fn_ext(file_path->str); |
| 6010 | |||
| 6011 |
2/2✓ Branch 0 taken 69 times.
✓ Branch 1 taken 8 times.
|
77 | for (const char **ext = hton->file_extensions; *ext; ext++) { |
| 6012 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 31 times.
|
69 | if (strcmp(file_ext, *ext) == 0) { |
| 6013 |
5/6✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 36 times.
|
40 | if (my_is_symlink(file_path->str, nullptr) && |
| 6014 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | test_if_data_home_dir(file_path->str)) { |
| 6015 | /* | ||
| 6016 | For safety reasons, if temporary table file is a symlink pointing | ||
| 6017 | to a file in the data directory, don't delete the file, delete | ||
| 6018 | symlink file only. It would be nicer to not delete symlinked files | ||
| 6019 | at all but MyISAM supports temporary tables with DATA | ||
| 6020 | DIRECTORY/INDEX DIRECTORY options. | ||
| 6021 | */ | ||
| 6022 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | (void)mysql_file_delete(key_file_misc, file_path->str, MYF(0)); |
| 6023 | } else | ||
| 6024 |
1/2✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
|
36 | (void)mysql_file_delete_with_symlink(key_file_misc, file_path->str, |
| 6025 | MYF(0)); | ||
| 6026 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
38 | files_it.remove(); |
| 6027 | 38 | break; | |
| 6028 | } | ||
| 6029 | } | ||
| 6030 | } | ||
| 6031 | 37671 | return false; | |
| 6032 | } | ||
| 6033 | |||
| 6034 | /***************************************************************************** | ||
| 6035 | Key cache handling. | ||
| 6036 | |||
| 6037 | This code is only relevant for ISAM/MyISAM tables | ||
| 6038 | |||
| 6039 | key_cache->cache may be 0 only in the case where a key cache is not | ||
| 6040 | initialized or when we where not able to init the key cache in a previous | ||
| 6041 | call to ha_init_key_cache() (probably out of memory) | ||
| 6042 | *****************************************************************************/ | ||
| 6043 | |||
| 6044 | /** | ||
| 6045 | Init a key cache if it has not been initied before. | ||
| 6046 | */ | ||
| 6047 | 9761 | int ha_init_key_cache(std::string_view, KEY_CACHE *key_cache) { | |
| 6048 |
1/2✓ Branch 0 taken 9761 times.
✗ Branch 1 not taken.
|
9761 | DBUG_TRACE; |
| 6049 | |||
| 6050 |
1/2✓ Branch 0 taken 9761 times.
✗ Branch 1 not taken.
|
9761 | if (!key_cache->key_cache_inited) { |
| 6051 |
1/2✓ Branch 0 taken 9761 times.
✗ Branch 1 not taken.
|
9761 | mysql_mutex_lock(&LOCK_global_system_variables); |
| 6052 | 9761 | size_t tmp_buff_size = (size_t)key_cache->param_buff_size; | |
| 6053 | 9761 | ulonglong tmp_block_size = key_cache->param_block_size; | |
| 6054 | 9761 | ulonglong division_limit = key_cache->param_division_limit; | |
| 6055 | 9761 | ulonglong age_threshold = key_cache->param_age_threshold; | |
| 6056 |
1/2✓ Branch 0 taken 9761 times.
✗ Branch 1 not taken.
|
9761 | mysql_mutex_unlock(&LOCK_global_system_variables); |
| 6057 |
1/2✓ Branch 0 taken 9761 times.
✗ Branch 1 not taken.
|
9761 | return !init_key_cache(key_cache, tmp_block_size, tmp_buff_size, |
| 6058 | 9761 | division_limit, age_threshold); | |
| 6059 | } | ||
| 6060 | ✗ | return 0; | |
| 6061 | 9761 | } | |
| 6062 | |||
| 6063 | /** | ||
| 6064 | Resize key cache. | ||
| 6065 | */ | ||
| 6066 | 101 | int ha_resize_key_cache(KEY_CACHE *key_cache) { | |
| 6067 |
1/2✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
|
101 | DBUG_TRACE; |
| 6068 | |||
| 6069 |
2/2✓ Branch 0 taken 99 times.
✓ Branch 1 taken 2 times.
|
101 | if (key_cache->key_cache_inited) { |
| 6070 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | mysql_mutex_lock(&LOCK_global_system_variables); |
| 6071 | 99 | size_t tmp_buff_size = (size_t)key_cache->param_buff_size; | |
| 6072 | 99 | ulonglong tmp_block_size = key_cache->param_block_size; | |
| 6073 | 99 | ulonglong division_limit = key_cache->param_division_limit; | |
| 6074 | 99 | ulonglong age_threshold = key_cache->param_age_threshold; | |
| 6075 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | mysql_mutex_unlock(&LOCK_global_system_variables); |
| 6076 | const int retval = | ||
| 6077 |
2/4✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
|
99 | resize_key_cache(key_cache, keycache_thread_var(), tmp_block_size, |
| 6078 | tmp_buff_size, division_limit, age_threshold); | ||
| 6079 | 99 | return !retval; | |
| 6080 | } | ||
| 6081 | 2 | return 0; | |
| 6082 | 101 | } | |
| 6083 | |||
| 6084 | /** | ||
| 6085 | Move all tables from one key cache to another one. | ||
| 6086 | */ | ||
| 6087 | 8 | int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache) { | |
| 6088 | 8 | mi_change_key_cache(old_key_cache, new_key_cache); | |
| 6089 | 8 | return 0; | |
| 6090 | } | ||
| 6091 | |||
| 6092 | struct st_discover_args { | ||
| 6093 | const char *db; | ||
| 6094 | const char *name; | ||
| 6095 | uchar **frmblob; | ||
| 6096 | size_t *frmlen; | ||
| 6097 | }; | ||
| 6098 | |||
| 6099 | 3828220 | static bool discover_handlerton(THD *thd, plugin_ref plugin, void *arg) { | |
| 6100 | 3828220 | st_discover_args *vargs = (st_discover_args *)arg; | |
| 6101 | 3828220 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 6102 |
4/6✓ Branch 0 taken 3823574 times.
✓ Branch 1 taken 4646 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3823574 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3828220 times.
|
3828220 | if (hton->state == SHOW_OPTION_YES && hton->discover && |
| 6103 | ✗ | (!(hton->discover(hton, thd, vargs->db, vargs->name, vargs->frmblob, | |
| 6104 | vargs->frmlen)))) | ||
| 6105 | ✗ | return true; | |
| 6106 | |||
| 6107 | 3828220 | return false; | |
| 6108 | } | ||
| 6109 | |||
| 6110 | /** | ||
| 6111 | Try to discover one table from handler(s). | ||
| 6112 | |||
| 6113 | @param[in] thd Thread context. | ||
| 6114 | @param[in] db Schema of table | ||
| 6115 | @param[in] name Name of table | ||
| 6116 | @param[out] frmblob Pointer to blob with table definition. | ||
| 6117 | @param[out] frmlen Length of the returned table definition blob | ||
| 6118 | |||
| 6119 | @retval | ||
| 6120 | -1 Table did not exists | ||
| 6121 | @retval | ||
| 6122 | 0 OK. Table could be discovered from SE. | ||
| 6123 | The *frmblob and *frmlen may be set if returning a blob | ||
| 6124 | which should be installed into data dictionary | ||
| 6125 | by the caller. | ||
| 6126 | |||
| 6127 | @retval | ||
| 6128 | >0 error. frmblob and frmlen may not be set | ||
| 6129 | |||
| 6130 | */ | ||
| 6131 | 598053 | static int ha_discover(THD *thd, const char *db, const char *name, | |
| 6132 | uchar **frmblob, size_t *frmlen) { | ||
| 6133 | 598053 | int error = -1; // Table does not exist in any handler | |
| 6134 |
1/2✓ Branch 0 taken 598055 times.
✗ Branch 1 not taken.
|
598053 | DBUG_TRACE; |
| 6135 |
5/8✓ Branch 0 taken 598055 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 598055 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 598019 times.
✓ Branch 6 taken 36 times.
✗ Branch 7 not taken.
|
598055 | DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); |
| 6136 | 598055 | st_discover_args args = {db, name, frmblob, frmlen}; | |
| 6137 | |||
| 6138 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 598050 times.
|
598055 | if (is_prefix(name, tmp_file_prefix)) /* skip temporary tables */ |
| 6139 | 5 | return error; | |
| 6140 | |||
| 6141 |
2/4✓ Branch 0 taken 598050 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 598050 times.
|
598050 | if (plugin_foreach(thd, discover_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, |
| 6142 | &args)) | ||
| 6143 | ✗ | error = 0; | |
| 6144 | |||
| 6145 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 598050 times.
|
598050 | if (!error) { |
| 6146 | ✗ | assert(!thd->status_var_aggregated); | |
| 6147 | ✗ | thd->status_var.ha_discover_count++; | |
| 6148 | } | ||
| 6149 | 598050 | return error; | |
| 6150 | 598055 | } | |
| 6151 | |||
| 6152 | /** | ||
| 6153 | Call this function in order to give the handler the possibility | ||
| 6154 | to ask engine if there are any new tables that should be written to disk | ||
| 6155 | or any dropped tables that need to be removed from disk | ||
| 6156 | */ | ||
| 6157 | struct st_find_files_args { | ||
| 6158 | const char *db; | ||
| 6159 | const char *path; | ||
| 6160 | const char *wild; | ||
| 6161 | bool dir; | ||
| 6162 | List<LEX_STRING> *files; | ||
| 6163 | }; | ||
| 6164 | |||
| 6165 | ✗ | static bool find_files_handlerton(THD *thd, plugin_ref plugin, void *arg) { | |
| 6166 | ✗ | st_find_files_args *vargs = (st_find_files_args *)arg; | |
| 6167 | ✗ | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 6168 | |||
| 6169 | ✗ | if (hton->state == SHOW_OPTION_YES && hton->find_files) | |
| 6170 | ✗ | if (hton->find_files(hton, thd, vargs->db, vargs->path, vargs->wild, | |
| 6171 | ✗ | vargs->dir, vargs->files)) | |
| 6172 | ✗ | return true; | |
| 6173 | |||
| 6174 | ✗ | return false; | |
| 6175 | } | ||
| 6176 | |||
| 6177 | ✗ | int ha_find_files(THD *thd, const char *db, const char *path, const char *wild, | |
| 6178 | bool dir, List<LEX_STRING> *files) { | ||
| 6179 | ✗ | int error = 0; | |
| 6180 | ✗ | DBUG_TRACE; | |
| 6181 | ✗ | DBUG_PRINT("enter", ("db: '%s' path: '%s' wild: '%s' dir: %d", db, path, | |
| 6182 | wild ? wild : "NULL", dir)); | ||
| 6183 | ✗ | st_find_files_args args = {db, path, wild, dir, files}; | |
| 6184 | |||
| 6185 | ✗ | plugin_foreach(thd, find_files_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, | |
| 6186 | &args); | ||
| 6187 | /* The return value is not currently used */ | ||
| 6188 | ✗ | return error; | |
| 6189 | } | ||
| 6190 | |||
| 6191 | /** | ||
| 6192 | Ask handler if the table exists in engine. | ||
| 6193 | @retval | ||
| 6194 | HA_ERR_NO_SUCH_TABLE Table does not exist | ||
| 6195 | @retval | ||
| 6196 | HA_ERR_TABLE_EXIST Table exists | ||
| 6197 | */ | ||
| 6198 | struct st_table_exists_in_engine_args { | ||
| 6199 | const char *db; | ||
| 6200 | const char *name; | ||
| 6201 | int err; | ||
| 6202 | }; | ||
| 6203 | |||
| 6204 | 3364114 | static bool table_exists_in_engine_handlerton(THD *thd, plugin_ref plugin, | |
| 6205 | void *arg) { | ||
| 6206 | 3364114 | st_table_exists_in_engine_args *vargs = (st_table_exists_in_engine_args *)arg; | |
| 6207 | 3364114 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 6208 | |||
| 6209 | 3364114 | int err = HA_ERR_NO_SUCH_TABLE; | |
| 6210 | |||
| 6211 |
3/4✓ Branch 0 taken 3356297 times.
✓ Branch 1 taken 7817 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3356297 times.
|
3364114 | if (hton->state == SHOW_OPTION_YES && hton->table_exists_in_engine) |
| 6212 | ✗ | err = hton->table_exists_in_engine(hton, thd, vargs->db, vargs->name); | |
| 6213 | |||
| 6214 | 3364114 | vargs->err = err; | |
| 6215 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3364114 times.
|
3364114 | if (vargs->err == HA_ERR_TABLE_EXIST) return true; |
| 6216 | |||
| 6217 | 3364114 | return false; | |
| 6218 | } | ||
| 6219 | |||
| 6220 | 316018 | int ha_table_exists_in_engine(THD *thd, const char *db, const char *name) { | |
| 6221 |
1/2✓ Branch 0 taken 316019 times.
✗ Branch 1 not taken.
|
316018 | DBUG_TRACE; |
| 6222 |
5/8✓ Branch 0 taken 316019 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 316018 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 315995 times.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
316019 | DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); |
| 6223 | 316018 | st_table_exists_in_engine_args args = {db, name, HA_ERR_NO_SUCH_TABLE}; | |
| 6224 |
1/2✓ Branch 0 taken 316019 times.
✗ Branch 1 not taken.
|
316018 | plugin_foreach(thd, table_exists_in_engine_handlerton, |
| 6225 | MYSQL_STORAGE_ENGINE_PLUGIN, &args); | ||
| 6226 |
5/8✓ Branch 0 taken 316019 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 316019 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 315996 times.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
316019 | DBUG_PRINT("exit", ("error: %d", args.err)); |
| 6227 | 316019 | return args.err; | |
| 6228 | 316019 | } | |
| 6229 | |||
| 6230 | /* | ||
| 6231 | TODO: change this into a dynamic struct | ||
| 6232 | List<handlerton> does not work as | ||
| 6233 | 1. binlog_end is called when MEM_ROOT is gone | ||
| 6234 | 2. cannot work with thd MEM_ROOT as memory should be freed | ||
| 6235 | */ | ||
| 6236 | #define MAX_HTON_LIST_ST 63 | ||
| 6237 | struct hton_list_st { | ||
| 6238 | handlerton *hton[MAX_HTON_LIST_ST]; | ||
| 6239 | uint sz; | ||
| 6240 | }; | ||
| 6241 | |||
| 6242 | struct binlog_func_st { | ||
| 6243 | enum_binlog_func fn; | ||
| 6244 | void *arg; | ||
| 6245 | }; | ||
| 6246 | |||
| 6247 | /** @brief | ||
| 6248 | Listing handlertons first to avoid recursive calls and deadlock | ||
| 6249 | */ | ||
| 6250 | 922397 | static bool binlog_func_list(THD *, plugin_ref plugin, void *arg) { | |
| 6251 | 922397 | hton_list_st *hton_list = (hton_list_st *)arg; | |
| 6252 | 922397 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 6253 |
3/4✓ Branch 0 taken 921727 times.
✓ Branch 1 taken 670 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 921727 times.
|
922397 | if (hton->state == SHOW_OPTION_YES && hton->binlog_func) { |
| 6254 | ✗ | uint sz = hton_list->sz; | |
| 6255 | ✗ | if (sz == MAX_HTON_LIST_ST - 1) { | |
| 6256 | /* list full */ | ||
| 6257 | ✗ | return false; | |
| 6258 | } | ||
| 6259 | ✗ | hton_list->hton[sz] = hton; | |
| 6260 | ✗ | hton_list->sz = sz + 1; | |
| 6261 | } | ||
| 6262 | 922397 | return false; | |
| 6263 | } | ||
| 6264 | |||
| 6265 | 84025 | static bool binlog_func_foreach(THD *thd, binlog_func_st *bfn) { | |
| 6266 | hton_list_st hton_list; | ||
| 6267 | uint i, sz; | ||
| 6268 | |||
| 6269 | 84025 | hton_list.sz = 0; | |
| 6270 |
1/2✓ Branch 0 taken 84025 times.
✗ Branch 1 not taken.
|
84025 | plugin_foreach(thd, binlog_func_list, MYSQL_STORAGE_ENGINE_PLUGIN, |
| 6271 | &hton_list); | ||
| 6272 | |||
| 6273 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 84025 times.
|
84025 | for (i = 0, sz = hton_list.sz; i < sz; i++) |
| 6274 | ✗ | hton_list.hton[i]->binlog_func(hton_list.hton[i], thd, bfn->fn, bfn->arg); | |
| 6275 | 84025 | return false; | |
| 6276 | } | ||
| 6277 | |||
| 6278 | 29142 | int ha_reset_logs(THD *thd) { | |
| 6279 | 29142 | binlog_func_st bfn = {BFN_RESET_LOGS, nullptr}; | |
| 6280 |
1/2✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
|
29142 | binlog_func_foreach(thd, &bfn); |
| 6281 | 29142 | return 0; | |
| 6282 | } | ||
| 6283 | |||
| 6284 | 12600 | void ha_reset_slave(THD *thd) { | |
| 6285 | 12600 | binlog_func_st bfn = {BFN_RESET_SLAVE, nullptr}; | |
| 6286 |
1/2✓ Branch 0 taken 12600 times.
✗ Branch 1 not taken.
|
12600 | binlog_func_foreach(thd, &bfn); |
| 6287 | 12600 | } | |
| 6288 | |||
| 6289 | 18790 | void ha_binlog_wait(THD *thd) { | |
| 6290 | 18790 | binlog_func_st bfn = {BFN_BINLOG_WAIT, nullptr}; | |
| 6291 |
1/2✓ Branch 0 taken 18790 times.
✗ Branch 1 not taken.
|
18790 | binlog_func_foreach(thd, &bfn); |
| 6292 | 18790 | } | |
| 6293 | |||
| 6294 | 15036 | int ha_binlog_index_purge_file(THD *thd, const char *file) { | |
| 6295 | 15036 | binlog_func_st bfn = {BFN_BINLOG_PURGE_FILE, const_cast<char *>(file)}; | |
| 6296 |
1/2✓ Branch 0 taken 15036 times.
✗ Branch 1 not taken.
|
15036 | binlog_func_foreach(thd, &bfn); |
| 6297 | 15036 | return 0; | |
| 6298 | } | ||
| 6299 | |||
| 6300 | struct binlog_log_query_st { | ||
| 6301 | enum_binlog_command binlog_command; | ||
| 6302 | const char *query; | ||
| 6303 | size_t query_length; | ||
| 6304 | const char *db; | ||
| 6305 | const char *table_name; | ||
| 6306 | }; | ||
| 6307 | |||
| 6308 | 188876 | static bool binlog_log_query_handlerton2(THD *thd, handlerton *hton, | |
| 6309 | void *args) { | ||
| 6310 | 188876 | struct binlog_log_query_st *b = (struct binlog_log_query_st *)args; | |
| 6311 |
3/4✓ Branch 0 taken 188815 times.
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 188815 times.
|
188876 | if (hton->state == SHOW_OPTION_YES && hton->binlog_log_query) |
| 6312 | ✗ | hton->binlog_log_query(hton, thd, b->binlog_command, b->query, | |
| 6313 | ✗ | b->query_length, b->db, b->table_name); | |
| 6314 | 188876 | return false; | |
| 6315 | } | ||
| 6316 | |||
| 6317 | 103180 | static bool binlog_log_query_handlerton(THD *thd, plugin_ref plugin, | |
| 6318 | void *args) { | ||
| 6319 | 103180 | return binlog_log_query_handlerton2(thd, plugin_data<handlerton *>(plugin), | |
| 6320 | 103180 | args); | |
| 6321 | } | ||
| 6322 | |||
| 6323 | 102179 | void ha_binlog_log_query(THD *thd, handlerton *hton, | |
| 6324 | enum_binlog_command binlog_command, const char *query, | ||
| 6325 | size_t query_length, const char *db, | ||
| 6326 | const char *table_name) { | ||
| 6327 | struct binlog_log_query_st b; | ||
| 6328 | 102179 | b.binlog_command = binlog_command; | |
| 6329 | 102179 | b.query = query; | |
| 6330 | 102179 | b.query_length = query_length; | |
| 6331 | 102179 | b.db = db; | |
| 6332 | 102179 | b.table_name = table_name; | |
| 6333 |
2/2✓ Branch 0 taken 16483 times.
✓ Branch 1 taken 85696 times.
|
102179 | if (hton == nullptr) |
| 6334 |
1/2✓ Branch 0 taken 16483 times.
✗ Branch 1 not taken.
|
16483 | plugin_foreach(thd, binlog_log_query_handlerton, |
| 6335 | MYSQL_STORAGE_ENGINE_PLUGIN, &b); | ||
| 6336 | else | ||
| 6337 |
1/2✓ Branch 0 taken 85696 times.
✗ Branch 1 not taken.
|
85696 | binlog_log_query_handlerton2(thd, hton, &b); |
| 6338 | 102179 | } | |
| 6339 | |||
| 6340 | 8457 | int ha_binlog_end(THD *thd) { | |
| 6341 | 8457 | binlog_func_st bfn = {BFN_BINLOG_END, nullptr}; | |
| 6342 |
1/2✓ Branch 0 taken 8457 times.
✗ Branch 1 not taken.
|
8457 | binlog_func_foreach(thd, &bfn); |
| 6343 | 8457 | return 0; | |
| 6344 | } | ||
| 6345 | |||
| 6346 | 353138 | static bool acl_notify_handlerton(THD *thd, plugin_ref plugin, void *data) { | |
| 6347 | 353138 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 6348 |
3/4✓ Branch 0 taken 353084 times.
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 353084 times.
|
353138 | if (hton->state == SHOW_OPTION_YES && hton->acl_notify) |
| 6349 | ✗ | hton->acl_notify(thd, | |
| 6350 | static_cast<const class Acl_change_notification *>(data)); | ||
| 6351 | 353138 | return false; | |
| 6352 | } | ||
| 6353 | |||
| 6354 | 32102 | void ha_acl_notify(THD *thd, class Acl_change_notification *data) { | |
| 6355 | 32102 | plugin_foreach(thd, acl_notify_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, data); | |
| 6356 | 32102 | } | |
| 6357 | |||
| 6358 | /** | ||
| 6359 | Calculate cost of 'index only' scan for given index and number of records | ||
| 6360 | |||
| 6361 | @param keynr Index number | ||
| 6362 | @param records Estimated number of records to be retrieved | ||
| 6363 | |||
| 6364 | @note | ||
| 6365 | It is assumed that we will read through the whole key range and that all | ||
| 6366 | key blocks are half full (normally things are much better). It is also | ||
| 6367 | assumed that each time we read the next key from the index, the handler | ||
| 6368 | performs a random seek, thus the cost is proportional to the number of | ||
| 6369 | blocks read. | ||
| 6370 | |||
| 6371 | @return | ||
| 6372 | Estimated cost of 'index only' scan | ||
| 6373 | */ | ||
| 6374 | |||
| 6375 | 12041827 | double handler::index_only_read_time(uint keynr, double records) { | |
| 6376 | double read_time; | ||
| 6377 | 12041827 | uint keys_per_block = | |
| 6378 | 12041827 | (stats.block_size / 2 / | |
| 6379 | 12041827 | (table_share->key_info[keynr].key_length + ref_length) + | |
| 6380 | 1); | ||
| 6381 | 12041827 | read_time = ((double)(records + keys_per_block - 1) / (double)keys_per_block); | |
| 6382 | 12041827 | return read_time; | |
| 6383 | } | ||
| 6384 | |||
| 6385 | 270439926 | double handler::table_in_memory_estimate() const { | |
| 6386 |
4/6✓ Branch 0 taken 66247383 times.
✓ Branch 1 taken 204192543 times.
✓ Branch 2 taken 66247488 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 66247578 times.
✗ Branch 5 not taken.
|
270439926 | assert(stats.table_in_mem_estimate == IN_MEMORY_ESTIMATE_UNKNOWN || |
| 6387 | (stats.table_in_mem_estimate >= 0.0 && | ||
| 6388 | stats.table_in_mem_estimate <= 1.0)); | ||
| 6389 | |||
| 6390 | /* | ||
| 6391 | If the storage engine has supplied information about how much of the | ||
| 6392 | table that is currently in a memory buffer, then use this estimate. | ||
| 6393 | */ | ||
| 6394 |
2/2✓ Branch 0 taken 66247553 times.
✓ Branch 1 taken 204192568 times.
|
270440121 | if (stats.table_in_mem_estimate != IN_MEMORY_ESTIMATE_UNKNOWN) |
| 6395 | 66247553 | return stats.table_in_mem_estimate; | |
| 6396 | |||
| 6397 | /* | ||
| 6398 | The storage engine has not provided any information about how much of | ||
| 6399 | this index is in memory, use an heuristic to produce an estimate. | ||
| 6400 | */ | ||
| 6401 | 204192568 | return estimate_in_memory_buffer(stats.data_file_length); | |
| 6402 | } | ||
| 6403 | |||
| 6404 | 12044041 | double handler::index_in_memory_estimate(uint keyno) const { | |
| 6405 | 12044041 | const KEY *key = &table->key_info[keyno]; | |
| 6406 | |||
| 6407 | /* | ||
| 6408 | If the storage engine has supplied information about how much of the | ||
| 6409 | index that is currently in a memory buffer, then use this estimate. | ||
| 6410 | */ | ||
| 6411 | 12044041 | const double est = key->in_memory_estimate(); | |
| 6412 |
2/2✓ Branch 0 taken 1942485 times.
✓ Branch 1 taken 10101598 times.
|
12044083 | if (est != IN_MEMORY_ESTIMATE_UNKNOWN) return est; |
| 6413 | |||
| 6414 | /* | ||
| 6415 | The storage engine has not provided any information about how much of | ||
| 6416 | this index is in memory, use an heuristic to produce an estimate. | ||
| 6417 | */ | ||
| 6418 | ulonglong file_length; | ||
| 6419 | |||
| 6420 | /* | ||
| 6421 | If the index is a clustered primary index, then use the data file | ||
| 6422 | size as estimate for how large the index is. | ||
| 6423 | */ | ||
| 6424 |
6/6✓ Branch 0 taken 25747 times.
✓ Branch 1 taken 10075851 times.
✓ Branch 2 taken 21434 times.
✓ Branch 3 taken 4313 times.
✓ Branch 4 taken 21434 times.
✓ Branch 5 taken 10080164 times.
|
10101598 | if (keyno == table->s->primary_key && primary_key_is_clustered()) |
| 6425 | 21434 | file_length = stats.data_file_length; | |
| 6426 | else | ||
| 6427 | 10080164 | file_length = stats.index_file_length; | |
| 6428 | |||
| 6429 | 10101598 | return estimate_in_memory_buffer(file_length); | |
| 6430 | } | ||
| 6431 | |||
| 6432 | 214294226 | double handler::estimate_in_memory_buffer(ulonglong table_index_size) const { | |
| 6433 | /* | ||
| 6434 | The storage engine has not provided any information about how much of | ||
| 6435 | the table/index is in memory. In this case we use a heuristic: | ||
| 6436 | |||
| 6437 | - if the size of the table/index is less than 20 percent (pick any | ||
| 6438 | number) of the memory buffer, then the entire table/index is likely in | ||
| 6439 | memory. | ||
| 6440 | - if the size of the table/index is larger than the memory buffer, then | ||
| 6441 | assume nothing of the table/index is in memory. | ||
| 6442 | - if the size of the table/index is larger than 20 percent but less than | ||
| 6443 | the memory buffer size, then use a linear function of the table/index | ||
| 6444 | size that goes from 1.0 to 0.0. | ||
| 6445 | */ | ||
| 6446 | |||
| 6447 | /* | ||
| 6448 | If the storage engine has information about the size of its | ||
| 6449 | memory buffer, then use this. Otherwise, assume that at least 100 MB | ||
| 6450 | of data can be cached in memory. | ||
| 6451 | */ | ||
| 6452 | 214294226 | longlong memory_buf_size = get_memory_buffer_size(); | |
| 6453 |
2/2✓ Branch 0 taken 210675693 times.
✓ Branch 1 taken 3618529 times.
|
214294222 | if (memory_buf_size <= 0) memory_buf_size = 100 * 1024 * 1024; // 100 MB |
| 6454 | |||
| 6455 | /* | ||
| 6456 | Upper limit for the relative size of a table to be considered | ||
| 6457 | entirely available in a memory buffer. If the actual table size is | ||
| 6458 | less than this we assume it is complete cached in a memory buffer. | ||
| 6459 | */ | ||
| 6460 | 214294222 | const double table_index_in_memory_limit = 0.2; | |
| 6461 | |||
| 6462 | /* | ||
| 6463 | Estimate for how much of the total memory buffer this table/index | ||
| 6464 | can occupy. | ||
| 6465 | */ | ||
| 6466 | 214294222 | const double percent_of_mem = | |
| 6467 | 214294222 | static_cast<double>(table_index_size) / memory_buf_size; | |
| 6468 | |||
| 6469 | double in_mem_est; | ||
| 6470 | |||
| 6471 |
2/2✓ Branch 0 taken 213890769 times.
✓ Branch 1 taken 403453 times.
|
214294222 | if (percent_of_mem < table_index_in_memory_limit) // Less than 20 percent |
| 6472 | 213890769 | in_mem_est = 1.0; | |
| 6473 |
2/2✓ Branch 0 taken 2078 times.
✓ Branch 1 taken 401375 times.
|
403453 | else if (percent_of_mem > 1.0) // Larger than buffer |
| 6474 | 2078 | in_mem_est = 0.0; | |
| 6475 | else { | ||
| 6476 | /* | ||
| 6477 | The size of the table/index is larger than | ||
| 6478 | "table_index_in_memory_limit" * "memory_buf_size" but less than | ||
| 6479 | the total size of the memory buffer. | ||
| 6480 | */ | ||
| 6481 | 401375 | in_mem_est = 1.0 - (percent_of_mem - table_index_in_memory_limit) / | |
| 6482 | (1.0 - table_index_in_memory_limit); | ||
| 6483 | } | ||
| 6484 |
2/4✓ Branch 0 taken 214294225 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 214294225 times.
✗ Branch 3 not taken.
|
214294222 | assert(in_mem_est >= 0.0 && in_mem_est <= 1.0); |
| 6485 | |||
| 6486 | 214294225 | return in_mem_est; | |
| 6487 | } | ||
| 6488 | |||
| 6489 | 212129766 | Cost_estimate handler::table_scan_cost() { | |
| 6490 | /* | ||
| 6491 | This function returns a Cost_estimate object. The function should be | ||
| 6492 | implemented in a way that allows the compiler to use "return value | ||
| 6493 | optimization" to avoid creating the temporary object for the return value | ||
| 6494 | and use of the copy constructor. | ||
| 6495 | */ | ||
| 6496 | |||
| 6497 | 212129766 | const double io_cost = scan_time() * table->cost_model()->page_read_cost(1.0); | |
| 6498 | 212130033 | Cost_estimate cost; | |
| 6499 | 212129855 | cost.add_io(io_cost); | |
| 6500 | 212129918 | return cost; | |
| 6501 | } | ||
| 6502 | |||
| 6503 | 12041830 | Cost_estimate handler::index_scan_cost(uint index, | |
| 6504 | double ranges [[maybe_unused]], | ||
| 6505 | double rows) { | ||
| 6506 | /* | ||
| 6507 | This function returns a Cost_estimate object. The function should be | ||
| 6508 | implemented in a way that allows the compiler to use "return value | ||
| 6509 | optimization" to avoid creating the temporary object for the return value | ||
| 6510 | and use of the copy constructor. | ||
| 6511 | */ | ||
| 6512 | |||
| 6513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12041830 times.
|
12041830 | assert(ranges >= 0.0); |
| 6514 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12041830 times.
|
12041830 | assert(rows >= 0.0); |
| 6515 | |||
| 6516 | 12041830 | const double io_cost = index_only_read_time(index, rows) * | |
| 6517 | 12041881 | table->cost_model()->page_read_cost_index(index, 1.0); | |
| 6518 | 12041901 | Cost_estimate cost; | |
| 6519 | 12041906 | cost.add_io(io_cost); | |
| 6520 | 12041907 | return cost; | |
| 6521 | } | ||
| 6522 | |||
| 6523 | 10893749 | Cost_estimate handler::read_cost(uint index, double ranges, double rows) { | |
| 6524 | /* | ||
| 6525 | This function returns a Cost_estimate object. The function should be | ||
| 6526 | implemented in a way that allows the compiler to use "return value | ||
| 6527 | optimization" to avoid creating the temporary object for the return value | ||
| 6528 | and use of the copy constructor. | ||
| 6529 | */ | ||
| 6530 | |||
| 6531 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10893749 times.
|
10893749 | assert(ranges >= 0.0); |
| 6532 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10893749 times.
|
10893749 | assert(rows >= 0.0); |
| 6533 | |||
| 6534 | const double io_cost = | ||
| 6535 | 10893749 | read_time(index, static_cast<uint>(ranges), static_cast<ha_rows>(rows)) * | |
| 6536 | 10893749 | table->cost_model()->page_read_cost(1.0); | |
| 6537 | 10893837 | Cost_estimate cost; | |
| 6538 | 10893845 | cost.add_io(io_cost); | |
| 6539 | 10893836 | return cost; | |
| 6540 | } | ||
| 6541 | |||
| 6542 | 9513939 | double handler::page_read_cost(uint index [[maybe_unused]], double reads) { | |
| 6543 | 9513939 | return table->cost_model()->page_read_cost(reads); | |
| 6544 | |||
| 6545 | ///////////////// | ||
| 6546 | // Other, non-page-based storage engine, may prefer to | ||
| 6547 | // override to; | ||
| 6548 | // return read_cost(index, 1, reads).total_cost(); | ||
| 6549 | |||
| 6550 | // Longer term: We should avoid mixed usage of read_cost() | ||
| 6551 | // and page_read_cost() from the optimizer. Use only | ||
| 6552 | // one of these to get cost estimates comparable between different | ||
| 6553 | // access methods and call paths. | ||
| 6554 | } | ||
| 6555 | |||
| 6556 | 7772495 | double handler::worst_seek_times(double reads) { | |
| 6557 | 7772495 | return table->cost_model()->page_read_cost(reads); | |
| 6558 | } | ||
| 6559 | |||
| 6560 | /** | ||
| 6561 | Check if key has partially-covered columns | ||
| 6562 | |||
| 6563 | We can't use DS-MRR to perform range scans when the ranges are over | ||
| 6564 | partially-covered keys, because we'll not have full key part values | ||
| 6565 | (we'll have their prefixes from the index) and will not be able to check | ||
| 6566 | if we've reached the end the range. | ||
| 6567 | |||
| 6568 | @param table Table to check keys for | ||
| 6569 | @param keyno Key to check | ||
| 6570 | |||
| 6571 | @todo | ||
| 6572 | Allow use of DS-MRR in cases where the index has partially-covered | ||
| 6573 | components but they are not used for scanning. | ||
| 6574 | |||
| 6575 | @retval true Yes | ||
| 6576 | @retval false No | ||
| 6577 | */ | ||
| 6578 | |||
| 6579 | 10210777 | static bool key_uses_partial_cols(TABLE *table, uint keyno) { | |
| 6580 | 10210777 | KEY_PART_INFO *kp = table->key_info[keyno].key_part; | |
| 6581 | 10210777 | KEY_PART_INFO *kp_end = kp + table->key_info[keyno].user_defined_key_parts; | |
| 6582 |
2/2✓ Branch 0 taken 10244883 times.
✓ Branch 1 taken 10209252 times.
|
20454135 | for (; kp != kp_end; kp++) { |
| 6583 |
2/2✓ Branch 0 taken 1525 times.
✓ Branch 1 taken 10243358 times.
|
10244883 | if (!kp->field->part_of_key.is_set(keyno)) return true; |
| 6584 | } | ||
| 6585 | 10209252 | return false; | |
| 6586 | } | ||
| 6587 | |||
| 6588 | /**************************************************************************** | ||
| 6589 | * Default MRR implementation (MRR to non-MRR converter) | ||
| 6590 | ***************************************************************************/ | ||
| 6591 | |||
| 6592 | /** | ||
| 6593 | Get cost and other information about MRR scan over a known list of ranges | ||
| 6594 | |||
| 6595 | Calculate estimated cost and other information about an MRR scan for given | ||
| 6596 | sequence of ranges. | ||
| 6597 | |||
| 6598 | @param keyno Index number | ||
| 6599 | @param seq Range sequence to be traversed | ||
| 6600 | @param seq_init_param First parameter for seq->init() | ||
| 6601 | @param n_ranges_arg Number of ranges in the sequence, or 0 if the caller | ||
| 6602 | can't efficiently determine it | ||
| 6603 | @param [in,out] bufsz IN: Size of the buffer available for use | ||
| 6604 | OUT: Size of the buffer that is expected to be actually | ||
| 6605 | used, or 0 if buffer is not needed. | ||
| 6606 | @param [in,out] flags A combination of HA_MRR_* flags | ||
| 6607 | @param [out] cost Estimated cost of MRR access | ||
| 6608 | |||
| 6609 | @note | ||
| 6610 | This method (or an overriding one in a derived class) must check for | ||
| 6611 | \c thd->killed and return HA_POS_ERROR if it is not zero. This is required | ||
| 6612 | for a user to be able to interrupt the calculation by killing the | ||
| 6613 | connection/query. | ||
| 6614 | |||
| 6615 | @retval | ||
| 6616 | HA_POS_ERROR Error or the engine is unable to perform the requested | ||
| 6617 | scan. Values of OUT parameters are undefined. | ||
| 6618 | @retval | ||
| 6619 | other OK, *cost contains cost of the scan, *bufsz and *flags | ||
| 6620 | contain scan parameters. | ||
| 6621 | */ | ||
| 6622 | |||
| 6623 | 10759204 | ha_rows handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, | |
| 6624 | void *seq_init_param, | ||
| 6625 | uint n_ranges_arg [[maybe_unused]], | ||
| 6626 | uint *bufsz, uint *flags, | ||
| 6627 | Cost_estimate *cost) { | ||
| 6628 | KEY_MULTI_RANGE range; | ||
| 6629 | range_seq_t seq_it; | ||
| 6630 | 10759204 | ha_rows rows, total_rows = 0; | |
| 6631 | 10759204 | uint n_ranges = 0; | |
| 6632 |
1/2✓ Branch 0 taken 10759229 times.
✗ Branch 1 not taken.
|
10759204 | THD *thd = current_thd; |
| 6633 | |||
| 6634 | /* Default MRR implementation doesn't need buffer */ | ||
| 6635 | 10759229 | *bufsz = 0; | |
| 6636 | |||
| 6637 |
3/4✓ Branch 0 taken 10759364 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10759363 times.
|
10759229 | DBUG_EXECUTE_IF("bug13822652_2", thd->killed = THD::KILL_QUERY;); |
| 6638 | |||
| 6639 |
1/2✓ Branch 0 taken 10759350 times.
✗ Branch 1 not taken.
|
10759364 | seq_it = seq->init(seq_init_param, n_ranges, *flags); |
| 6640 |
3/4✓ Branch 0 taken 21561534 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10802231 times.
✓ Branch 3 taken 10759303 times.
|
21561547 | while (!seq->next(seq_it, &range)) { |
| 6641 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10802267 times.
|
10802231 | if (unlikely(thd->killed != 0)) return HA_POS_ERROR; |
| 6642 | |||
| 6643 | 10802267 | n_ranges++; | |
| 6644 | key_range *min_endp, *max_endp; | ||
| 6645 |
2/2✓ Branch 0 taken 643 times.
✓ Branch 1 taken 10801624 times.
|
10802267 | if (range.range_flag & GEOM_FLAG) { |
| 6646 | 643 | min_endp = &range.start_key; | |
| 6647 | 643 | max_endp = nullptr; | |
| 6648 | } else { | ||
| 6649 |
2/2✓ Branch 0 taken 10793439 times.
✓ Branch 1 taken 8185 times.
|
10801624 | min_endp = range.start_key.length ? &range.start_key : nullptr; |
| 6650 |
2/2✓ Branch 0 taken 626747 times.
✓ Branch 1 taken 10174877 times.
|
10801624 | max_endp = range.end_key.length ? &range.end_key : nullptr; |
| 6651 | } | ||
| 6652 | |||
| 6653 | /* | ||
| 6654 | Return HA_POS_ERROR if the specified keyno is not capable of | ||
| 6655 | serving the specified range request. The cases checked for are: | ||
| 6656 | |||
| 6657 | 1) The range contain NULL values and the specified index will | ||
| 6658 | fallback to do a full table scan if it find NULLs in the keys. | ||
| 6659 | 2) The range does not specify all key parts and the key | ||
| 6660 | cannot provide partial key searches. | ||
| 6661 | */ | ||
| 6662 |
3/4✓ Branch 0 taken 3804 times.
✓ Branch 1 taken 10798463 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10802267 times.
|
10806071 | if (range.range_flag & NULL_RANGE && // 1) |
| 6663 |
2/4✓ Branch 0 taken 3804 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3804 times.
|
3804 | table->file->index_flags(keyno, 0, false) & HA_TABLE_SCAN_ON_NULL) { |
| 6664 | // The NULL_RANGE will result in a full TABLE_SCAN, reject it. | ||
| 6665 | ✗ | return HA_POS_ERROR; | |
| 6666 | } | ||
| 6667 |
2/2✓ Branch 0 taken 596716 times.
✓ Branch 1 taken 10205551 times.
|
10802267 | if (!(range.range_flag & EQ_RANGE) || // 2) |
| 6668 |
2/2✓ Branch 0 taken 179260 times.
✓ Branch 1 taken 417456 times.
|
596716 | range.start_key.length < table->key_info[keyno].key_length) { |
| 6669 | // A full EQ-range was not specified, reject if not OK by index. | ||
| 6670 |
3/4✓ Branch 0 taken 10384763 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 10384747 times.
|
10384811 | if (index_flags(keyno, 0, false) & HA_ONLY_WHOLE_INDEX) { |
| 6671 | 16 | return HA_POS_ERROR; | |
| 6672 | } | ||
| 6673 | } | ||
| 6674 | |||
| 6675 | /* | ||
| 6676 | Get the number of rows in the range. This is done by calling | ||
| 6677 | records_in_range() unless: | ||
| 6678 | |||
| 6679 | 1) The index is unique. | ||
| 6680 | There cannot be more than one matching row, so 1 is | ||
| 6681 | assumed. Note that it is possible that the correct number | ||
| 6682 | is actually 0, so the row estimate may be too high in this | ||
| 6683 | case. Also note: ranges of the form "x IS NULL" may have more | ||
| 6684 | than 1 matching row so records_in_range() is called for these. | ||
| 6685 | 2) SKIP_RECORDS_IN_RANGE will be set when skip_records_in_range or | ||
| 6686 | use_index_statistics are true. | ||
| 6687 | Ranges of the form "x IS NULL" will not use index statistics | ||
| 6688 | because the number of rows with this value are likely to be | ||
| 6689 | very different than the values in the index statistics. | ||
| 6690 | |||
| 6691 | Note: With SKIP_RECORDS_IN_RANGE, use Index statistics if: | ||
| 6692 | a) Index statistics is available. | ||
| 6693 | b) The range is an equality range but the index is either not | ||
| 6694 | unique or all of the keyparts are not used. | ||
| 6695 | */ | ||
| 6696 | 10802203 | int keyparts_used = 0; | |
| 6697 |
2/2✓ Branch 0 taken 144060 times.
✓ Branch 1 taken 10658143 times.
|
10802203 | if ((range.range_flag & UNIQUE_RANGE) && // 1) |
| 6698 |
2/2✓ Branch 0 taken 143536 times.
✓ Branch 1 taken 524 times.
|
144060 | !(range.range_flag & NULL_RANGE)) |
| 6699 | 143536 | rows = 1; /* there can be at most one row */ | |
| 6700 |
2/2✓ Branch 0 taken 1247 times.
✓ Branch 1 taken 10657420 times.
|
10658667 | else if (range.range_flag & SKIP_RECORDS_IN_RANGE && // 2) |
| 6701 |
2/2✓ Branch 0 taken 1246 times.
✓ Branch 1 taken 1 times.
|
1247 | !(range.range_flag & NULL_RANGE)) { |
| 6702 | 3708 | if ((range.range_flag & EQ_RANGE) && | |
| 6703 |
7/8✓ Branch 0 taken 1216 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 1216 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1082 times.
✓ Branch 5 taken 134 times.
✓ Branch 6 taken 1082 times.
✓ Branch 7 taken 164 times.
|
2462 | (keyparts_used = my_count_bits(range.start_key.keypart_map)) && |
| 6704 | 1216 | table->key_info[keyno].has_records_per_key(keyparts_used - 1)) { | |
| 6705 | 1082 | rows = static_cast<ha_rows>( | |
| 6706 | 1082 | table->key_info[keyno].records_per_key(keyparts_used - 1)); | |
| 6707 | } else { | ||
| 6708 | /* | ||
| 6709 | Since records_in_range has not been called, set the rows to 1. | ||
| 6710 | FORCE INDEX has been used, cost model values will be ignored anyway. | ||
| 6711 | */ | ||
| 6712 | 164 | rows = 1; | |
| 6713 | } | ||
| 6714 | } else { | ||
| 6715 |
2/6✓ Branch 0 taken 10657429 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10657429 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
10657421 | DBUG_EXECUTE_IF("crash_records_in_range", DBUG_SUICIDE();); |
| 6716 |
3/4✓ Branch 0 taken 8187 times.
✓ Branch 1 taken 10649242 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8187 times.
|
10657429 | assert(min_endp || max_endp); |
| 6717 |
1/2✓ Branch 0 taken 10657430 times.
✗ Branch 1 not taken.
|
10657429 | rows = table->pos_in_table_list->is_derived_unfinished_materialization() |
| 6718 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10657430 times.
|
10657430 | ? HA_POS_ERROR |
| 6719 |
1/2✓ Branch 0 taken 10657433 times.
✗ Branch 1 not taken.
|
10657430 | : this->records_in_range(keyno, min_endp, max_endp); |
| 6720 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 10657415 times.
|
10657433 | if (rows == HA_POS_ERROR) { |
| 6721 | /* Can't scan one range => can't do MRR scan at all */ | ||
| 6722 | 18 | return HA_POS_ERROR; | |
| 6723 | } | ||
| 6724 | } | ||
| 6725 | 10802197 | total_rows += rows; | |
| 6726 | } | ||
| 6727 | |||
| 6728 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10759303 times.
|
10759303 | assert(total_rows != HA_POS_ERROR); |
| 6729 | { | ||
| 6730 | 10759303 | const Cost_model_table *const cost_model = table->cost_model(); | |
| 6731 | |||
| 6732 | /* The following calculation is the same as in multi_range_read_info(): */ | ||
| 6733 | 10759285 | *flags |= (HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SUPPORT_SORTED); | |
| 6734 | |||
| 6735 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10759260 times.
|
10759285 | assert(cost->is_zero()); |
| 6736 |
2/2✓ Branch 0 taken 226802 times.
✓ Branch 1 taken 10532458 times.
|
10759260 | if (*flags & HA_MRR_INDEX_ONLY) |
| 6737 |
1/2✓ Branch 0 taken 226802 times.
✗ Branch 1 not taken.
|
226802 | *cost = index_scan_cost(keyno, static_cast<double>(n_ranges), |
| 6738 | static_cast<double>(total_rows)); | ||
| 6739 | else | ||
| 6740 |
1/2✓ Branch 0 taken 10532507 times.
✗ Branch 1 not taken.
|
10532458 | *cost = read_cost(keyno, static_cast<double>(n_ranges), |
| 6741 | static_cast<double>(total_rows)); | ||
| 6742 | 10759284 | cost->add_cpu( | |
| 6743 | 10759309 | cost_model->row_evaluate_cost(static_cast<double>(total_rows)) + 0.01); | |
| 6744 | } | ||
| 6745 | 10759301 | return total_rows; | |
| 6746 | } | ||
| 6747 | |||
| 6748 | /** | ||
| 6749 | Get cost and other information about MRR scan over some sequence of ranges | ||
| 6750 | |||
| 6751 | Calculate estimated cost and other information about an MRR scan for some | ||
| 6752 | sequence of ranges. | ||
| 6753 | |||
| 6754 | The ranges themselves will be known only at execution phase. When this | ||
| 6755 | function is called we only know number of ranges and a (rough) E(#records) | ||
| 6756 | within those ranges. | ||
| 6757 | |||
| 6758 | Currently this function is only called for "n-keypart singlepoint" ranges, | ||
| 6759 | i.e. each range is "keypart1=someconst1 AND ... AND keypartN=someconstN" | ||
| 6760 | |||
| 6761 | The flags parameter is a combination of those flags: HA_MRR_SORTED, | ||
| 6762 | HA_MRR_INDEX_ONLY, HA_MRR_NO_ASSOCIATION, HA_MRR_LIMITS. | ||
| 6763 | |||
| 6764 | @param keyno Index number | ||
| 6765 | @param n_ranges Estimated number of ranges (i.e. intervals) in the | ||
| 6766 | range sequence. | ||
| 6767 | @param n_rows Estimated total number of records contained within all | ||
| 6768 | of the ranges | ||
| 6769 | @param [in,out] bufsz IN: Size of the buffer available for use | ||
| 6770 | OUT: Size of the buffer that will be actually used, or | ||
| 6771 | 0 if buffer is not needed. | ||
| 6772 | @param [in,out] flags A combination of HA_MRR_* flags | ||
| 6773 | @param [out] cost Estimated cost of MRR access | ||
| 6774 | |||
| 6775 | @retval | ||
| 6776 | 0 OK, *cost contains cost of the scan, *bufsz and *flags contain scan | ||
| 6777 | parameters. | ||
| 6778 | @retval | ||
| 6779 | other Error or can't perform the requested scan | ||
| 6780 | */ | ||
| 6781 | |||
| 6782 | 5452 | ha_rows handler::multi_range_read_info(uint keyno, uint n_ranges, uint n_rows, | |
| 6783 | uint *bufsz, uint *flags, | ||
| 6784 | Cost_estimate *cost) { | ||
| 6785 | 5452 | *bufsz = 0; /* Default implementation doesn't need a buffer */ | |
| 6786 | |||
| 6787 | 5452 | *flags |= HA_MRR_USE_DEFAULT_IMPL; | |
| 6788 | 5452 | *flags |= HA_MRR_SUPPORT_SORTED; | |
| 6789 | |||
| 6790 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5452 times.
|
5452 | assert(cost->is_zero()); |
| 6791 | |||
| 6792 | /* Produce the same cost as non-MRR code does */ | ||
| 6793 |
2/2✓ Branch 0 taken 1884 times.
✓ Branch 1 taken 3568 times.
|
5452 | if (*flags & HA_MRR_INDEX_ONLY) |
| 6794 | 1884 | *cost = index_scan_cost(keyno, n_ranges, n_rows); | |
| 6795 | else | ||
| 6796 | 3568 | *cost = read_cost(keyno, n_ranges, n_rows); | |
| 6797 | 5452 | return 0; | |
| 6798 | } | ||
| 6799 | |||
| 6800 | /** | ||
| 6801 | Initialize the MRR scan. | ||
| 6802 | |||
| 6803 | This function may do heavyweight scan | ||
| 6804 | initialization like row prefetching/sorting/etc (NOTE: but better not do | ||
| 6805 | it here as we may not need it, e.g. if we never satisfy WHERE clause on | ||
| 6806 | previous tables. For many implementations it would be natural to do such | ||
| 6807 | initializations in the first multi_read_range_next() call) | ||
| 6808 | |||
| 6809 | mode is a combination of the following flags: HA_MRR_SORTED, | ||
| 6810 | HA_MRR_INDEX_ONLY, HA_MRR_NO_ASSOCIATION | ||
| 6811 | |||
| 6812 | @param seq_funcs Range sequence to be traversed | ||
| 6813 | @param seq_init_param First parameter for seq->init() | ||
| 6814 | @param n_ranges Number of ranges in the sequence | ||
| 6815 | @param mode Flags, see the description section for the details | ||
| 6816 | @param buf INOUT: memory buffer to be used | ||
| 6817 | |||
| 6818 | @note | ||
| 6819 | One must have called index_init() before calling this function. Several | ||
| 6820 | multi_range_read_init() calls may be made in course of one query. | ||
| 6821 | |||
| 6822 | Until WL#2623 is done (see its text, section 3.2), the following will | ||
| 6823 | also hold: | ||
| 6824 | The caller will guarantee that if "seq->init == mrr_ranges_array_init" | ||
| 6825 | then seq_init_param is an array of n_ranges KEY_MULTI_RANGE structures. | ||
| 6826 | This property will only be used by NDB handler until WL#2623 is done. | ||
| 6827 | |||
| 6828 | Buffer memory management is done according to the following scenario: | ||
| 6829 | The caller allocates the buffer and provides it to the callee by filling | ||
| 6830 | the members of HANDLER_BUFFER structure. | ||
| 6831 | The callee consumes all or some fraction of the provided buffer space, and | ||
| 6832 | sets the HANDLER_BUFFER members accordingly. | ||
| 6833 | The callee may use the buffer memory until the next multi_range_read_init() | ||
| 6834 | call is made, all records have been read, or until index_end() call is | ||
| 6835 | made, whichever comes first. | ||
| 6836 | |||
| 6837 | @retval 0 OK | ||
| 6838 | @retval 1 Error | ||
| 6839 | */ | ||
| 6840 | |||
| 6841 | 10739119 | int handler::multi_range_read_init(RANGE_SEQ_IF *seq_funcs, | |
| 6842 | void *seq_init_param, uint n_ranges, | ||
| 6843 | uint mode, | ||
| 6844 | HANDLER_BUFFER *buf [[maybe_unused]]) { | ||
| 6845 |
1/2✓ Branch 0 taken 10739241 times.
✗ Branch 1 not taken.
|
10739119 | DBUG_TRACE; |
| 6846 |
1/2✓ Branch 0 taken 10739226 times.
✗ Branch 1 not taken.
|
10739241 | mrr_iter = seq_funcs->init(seq_init_param, n_ranges, mode); |
| 6847 | 10739226 | mrr_funcs = *seq_funcs; | |
| 6848 | 10739226 | mrr_is_output_sorted = mode & HA_MRR_SORTED; | |
| 6849 | 10739226 | mrr_have_range = false; | |
| 6850 | 10739253 | return 0; | |
| 6851 | 10739226 | } | |
| 6852 | |||
| 6853 | 13979626 | int handler::ha_multi_range_read_next(char **range_info) { | |
| 6854 | int result; | ||
| 6855 |
1/2✓ Branch 0 taken 13979686 times.
✗ Branch 1 not taken.
|
13979626 | DBUG_TRACE; |
| 6856 | |||
| 6857 | // Set status for the need to update generated fields | ||
| 6858 | 13979686 | m_update_generated_read_fields = table->has_gcol(); | |
| 6859 | |||
| 6860 |
1/2✓ Branch 0 taken 13979703 times.
✗ Branch 1 not taken.
|
13979661 | result = multi_range_read_next(range_info); |
| 6861 |
4/4✓ Branch 0 taken 3442967 times.
✓ Branch 1 taken 10536736 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 3442921 times.
|
13979703 | if (!result && m_update_generated_read_fields) { |
| 6862 | 46 | result = | |
| 6863 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | update_generated_read_fields(table->record[0], table, active_index); |
| 6864 | 46 | m_update_generated_read_fields = false; | |
| 6865 | } | ||
| 6866 | 13979703 | table->set_row_status_from_handler(result); | |
| 6867 | 13979705 | return result; | |
| 6868 | 13979703 | } | |
| 6869 | |||
| 6870 | /** | ||
| 6871 | Get next record in MRR scan | ||
| 6872 | |||
| 6873 | Default MRR implementation: read the next record | ||
| 6874 | |||
| 6875 | @param range_info OUT Undefined if HA_MRR_NO_ASSOCIATION flag is in effect | ||
| 6876 | Otherwise, the opaque value associated with the range | ||
| 6877 | that contains the returned record. | ||
| 6878 | |||
| 6879 | @retval 0 OK | ||
| 6880 | @retval other Error code | ||
| 6881 | */ | ||
| 6882 | |||
| 6883 | 13979785 | int handler::multi_range_read_next(char **range_info) { | |
| 6884 | 13979785 | int result = HA_ERR_END_OF_FILE; | |
| 6885 | 13979785 | int range_res = 0; | |
| 6886 | 13979785 | bool dup_found = false; | |
| 6887 |
1/2✓ Branch 0 taken 13979860 times.
✗ Branch 1 not taken.
|
13979785 | DBUG_TRACE; |
| 6888 | // For a multi-valued index the unique filter have to be used for correct | ||
| 6889 | // result | ||
| 6890 |
3/4✓ Branch 0 taken 849 times.
✓ Branch 1 taken 13979011 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 849 times.
|
13979860 | assert(!(table->key_info[active_index].flags & HA_MULTI_VALUED_KEY) || |
| 6891 | m_unique); | ||
| 6892 | |||
| 6893 |
2/2✓ Branch 0 taken 10538634 times.
✓ Branch 1 taken 3441226 times.
|
13979860 | if (!mrr_have_range) { |
| 6894 | 10538634 | mrr_have_range = true; | |
| 6895 | 10538634 | goto start; | |
| 6896 | } | ||
| 6897 | |||
| 6898 | do { | ||
| 6899 | /* | ||
| 6900 | Do not call read_range_next() if its equality on a unique | ||
| 6901 | index. | ||
| 6902 | */ | ||
| 6903 |
2/2✓ Branch 0 taken 119518 times.
✓ Branch 1 taken 3322041 times.
|
3441559 | if (!((mrr_cur_range.range_flag & UNIQUE_RANGE) && |
| 6904 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 119519 times.
|
119518 | (mrr_cur_range.range_flag & EQ_RANGE))) { |
| 6905 |
3/4✓ Branch 0 taken 3321708 times.
✓ Branch 1 taken 332 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3321708 times.
|
3322040 | assert(!result || result == HA_ERR_END_OF_FILE); |
| 6906 |
1/2✓ Branch 0 taken 3322041 times.
✗ Branch 1 not taken.
|
3322040 | result = read_range_next(); |
| 6907 |
2/4✓ Branch 0 taken 3322041 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3322041 times.
|
3322041 | DBUG_EXECUTE_IF("bug20162055_DEADLOCK", result = HA_ERR_LOCK_DEADLOCK;); |
| 6908 | /* | ||
| 6909 | On success check loop condition to filter duplicates, if needed. | ||
| 6910 | Exit on non-EOF error. Use next range on EOF error. | ||
| 6911 | */ | ||
| 6912 |
2/2✓ Branch 0 taken 3106732 times.
✓ Branch 1 taken 215309 times.
|
3322041 | if (!result) continue; |
| 6913 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 215307 times.
|
215309 | if (result != HA_ERR_END_OF_FILE) break; |
| 6914 | } else { | ||
| 6915 |
2/4✓ Branch 0 taken 119517 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 119517 times.
|
119519 | if (was_semi_consistent_read()) goto scan_it_again; |
| 6916 | } | ||
| 6917 | |||
| 6918 | 119517 | start: | |
| 6919 | /* Try the next range(s) until one matches a record. */ | ||
| 6920 |
3/4✓ Branch 0 taken 21099710 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10563018 times.
✓ Branch 3 taken 10536692 times.
|
21099778 | while (!(range_res = mrr_funcs.next(mrr_iter, &mrr_cur_range))) { |
| 6921 | 10563018 | scan_it_again: | |
| 6922 |
1/2✓ Branch 0 taken 10563129 times.
✗ Branch 1 not taken.
|
21126036 | result = read_range_first( |
| 6923 |
2/2✓ Branch 0 taken 10558407 times.
✓ Branch 1 taken 4611 times.
|
10563018 | mrr_cur_range.start_key.keypart_map ? &mrr_cur_range.start_key |
| 6924 | : nullptr, | ||
| 6925 | 10563018 | mrr_cur_range.end_key.keypart_map ? &mrr_cur_range.end_key : nullptr, | |
| 6926 |
2/2✓ Branch 0 taken 396127 times.
✓ Branch 1 taken 10166891 times.
|
10563018 | mrr_cur_range.range_flag & EQ_RANGE, mrr_is_output_sorted); |
| 6927 |
2/2✓ Branch 0 taken 336809 times.
✓ Branch 1 taken 10226320 times.
|
10563129 | if (result != HA_ERR_END_OF_FILE) break; |
| 6928 | } | ||
| 6929 | 3443541 | } while (((result == HA_ERR_END_OF_FILE) || | |
| 6930 |
11/12✓ Branch 0 taken 3443541 times.
✓ Branch 1 taken 10536692 times.
✓ Branch 2 taken 1062 times.
✓ Branch 3 taken 3442479 times.
✓ Branch 4 taken 1062 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 333 times.
✓ Branch 7 taken 729 times.
✓ Branch 8 taken 333 times.
✓ Branch 9 taken 10536692 times.
✓ Branch 10 taken 333 times.
✓ Branch 11 taken 13979900 times.
|
13980233 | (m_unique && (dup_found = filter_dup_records()))) && |
| 6931 | !range_res); | ||
| 6932 | |||
| 6933 | 13979902 | *range_info = mrr_cur_range.ptr; | |
| 6934 | /* | ||
| 6935 | Last found record was a duplicate and we retrieved records from all | ||
| 6936 | ranges, so no more records can be returned. | ||
| 6937 | */ | ||
| 6938 |
3/4✓ Branch 0 taken 32 times.
✓ Branch 1 taken 13979870 times.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
13979902 | if (dup_found && range_res) result = HA_ERR_END_OF_FILE; |
| 6939 | |||
| 6940 |
5/8✓ Branch 0 taken 13979887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13979887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 13979879 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
|
13979902 | DBUG_PRINT("exit", ("handler::multi_range_read_next result %d", result)); |
| 6941 | 13979887 | return result; | |
| 6942 | 13979887 | } | |
| 6943 | |||
| 6944 | /**************************************************************************** | ||
| 6945 | * DS-MRR implementation | ||
| 6946 | ***************************************************************************/ | ||
| 6947 | |||
| 6948 | /** | ||
| 6949 | DS-MRR: Initialize and start MRR scan | ||
| 6950 | |||
| 6951 | Initialize and start the MRR scan. Depending on the mode parameter, this | ||
| 6952 | may use default or DS-MRR implementation. | ||
| 6953 | |||
| 6954 | The DS-MRR implementation will use a second handler object (h2) for | ||
| 6955 | doing scan on the index: | ||
| 6956 | - on the first call to this function the h2 handler will be created | ||
| 6957 | and h2 will be opened using the same index as the main handler | ||
| 6958 | is set to use. The index scan on the main index will be closed | ||
| 6959 | and it will be re-opened to read records from the table using either | ||
| 6960 | no key or the primary key. The h2 handler will be deleted when | ||
| 6961 | reset() is called (which should happen on the end of the statement). | ||
| 6962 | - when dsmrr_close() is called the index scan on h2 is closed. | ||
| 6963 | - on following calls to this function one of the following must be valid: | ||
| 6964 | a. if dsmrr_close has been called: | ||
| 6965 | the main handler (h) must be open on an index, h2 will be opened | ||
| 6966 | using this index, and the index on h will be closed and | ||
| 6967 | h will be re-opened to read reads from the table using either | ||
| 6968 | no key or the primary key. | ||
| 6969 | b. dsmrr_close has not been called: | ||
| 6970 | h2 will already be open, the main handler h must be set up | ||
| 6971 | to read records from the table (handler->inited is RND) either | ||
| 6972 | using the primary index or using no index at all. | ||
| 6973 | |||
| 6974 | @param seq_funcs Interval sequence enumeration functions | ||
| 6975 | @param seq_init_param Interval sequence enumeration parameter | ||
| 6976 | @param n_ranges Number of ranges in the sequence. | ||
| 6977 | @param mode HA_MRR_* modes to use | ||
| 6978 | @param[in,out] buf Buffer to use | ||
| 6979 | |||
| 6980 | @retval 0 Ok, Scan started. | ||
| 6981 | @retval other Error | ||
| 6982 | */ | ||
| 6983 | |||
| 6984 | 10725576 | int DsMrr_impl::dsmrr_init(RANGE_SEQ_IF *seq_funcs, void *seq_init_param, | |
| 6985 | uint n_ranges, uint mode, HANDLER_BUFFER *buf) { | ||
| 6986 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10725576 times.
|
10725576 | assert(table != nullptr); // Verify init() called |
| 6987 | |||
| 6988 | uint elem_size; | ||
| 6989 | 10725576 | int retval = 0; | |
| 6990 |
1/2✓ Branch 0 taken 10725705 times.
✗ Branch 1 not taken.
|
10725576 | DBUG_TRACE; |
| 6991 | 10725705 | THD *const thd = table->in_use; // current THD | |
| 6992 | |||
| 6993 |
1/2✓ Branch 0 taken 10725700 times.
✗ Branch 1 not taken.
|
10725705 | if (!hint_key_state(thd, table->pos_in_table_list, h->active_index, |
| 6994 |
4/4✓ Branch 0 taken 10704418 times.
✓ Branch 1 taken 21282 times.
✓ Branch 2 taken 660669 times.
✓ Branch 3 taken 10065031 times.
|
21430118 | MRR_HINT_ENUM, OPTIMIZER_SWITCH_MRR) || |
| 6995 |
2/2✓ Branch 0 taken 639392 times.
✓ Branch 1 taken 10065026 times.
|
10704418 | mode & (HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED)) // DS-MRR doesn't sort |
| 6996 | { | ||
| 6997 | 660669 | use_default_impl = true; | |
| 6998 |
1/2✓ Branch 0 taken 660703 times.
✗ Branch 1 not taken.
|
660669 | retval = h->handler::multi_range_read_init(seq_funcs, seq_init_param, |
| 6999 | n_ranges, mode, buf); | ||
| 7000 | 660703 | return retval; | |
| 7001 | } | ||
| 7002 | |||
| 7003 | /* | ||
| 7004 | This assert will hit if we have pushed an index condition to the | ||
| 7005 | primary key index and then "change our mind" and use a different | ||
| 7006 | index for retrieving data with MRR. One of the following criteria | ||
| 7007 | must be true: | ||
| 7008 | 1. We have not pushed an index condition on this handler. | ||
| 7009 | 2. We have pushed an index condition and this is on the currently used | ||
| 7010 | index. | ||
| 7011 | 3. We have pushed an index condition but this is not for the primary key. | ||
| 7012 | 4. We have pushed an index condition and this has been transferred to | ||
| 7013 | the clone (h2) of the handler object. | ||
| 7014 | */ | ||
| 7015 |
3/10✓ Branch 0 taken 232 times.
✓ Branch 1 taken 10064799 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 232 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
10065031 | assert(!h->pushed_idx_cond || h->pushed_idx_cond_keyno == h->active_index || |
| 7016 | h->pushed_idx_cond_keyno != table->s->primary_key || | ||
| 7017 | (h2 && h->pushed_idx_cond_keyno == h2->active_index)); | ||
| 7018 | |||
| 7019 | 10065031 | rowids_buf = buf->buffer; | |
| 7020 | |||
| 7021 | 10065031 | is_mrr_assoc = !(mode & HA_MRR_NO_ASSOCIATION); | |
| 7022 | |||
| 7023 |
2/2✓ Branch 0 taken 4677 times.
✓ Branch 1 taken 10060354 times.
|
10065031 | if (is_mrr_assoc) { |
| 7024 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4677 times.
|
4677 | assert(!thd->status_var_aggregated); |
| 7025 | 4677 | table->in_use->status_var.ha_multi_range_read_init_count++; | |
| 7026 | } | ||
| 7027 | |||
| 7028 | 10065031 | rowids_buf_end = buf->buffer_end; | |
| 7029 | 10065031 | elem_size = h->ref_length + (int)is_mrr_assoc * sizeof(void *); | |
| 7030 | 10065031 | rowids_buf_last = | |
| 7031 | 10065031 | rowids_buf + ((rowids_buf_end - rowids_buf) / elem_size) * elem_size; | |
| 7032 | 10065031 | rowids_buf_end = rowids_buf_last; | |
| 7033 | |||
| 7034 | /* | ||
| 7035 | The DS-MRR scan uses a second handler object (h2) for doing the | ||
| 7036 | index scan. Create this by cloning the primary handler | ||
| 7037 | object. The h2 handler object is deleted when DsMrr_impl::reset() | ||
| 7038 | is called. | ||
| 7039 | */ | ||
| 7040 |
2/2✓ Branch 0 taken 566 times.
✓ Branch 1 taken 10064465 times.
|
10065031 | if (!h2) { |
| 7041 | handler *new_h2; | ||
| 7042 | /* | ||
| 7043 | ::clone() takes up a lot of stack, especially on 64 bit platforms. | ||
| 7044 | The constant 5 is an empiric result. | ||
| 7045 | @todo Is this still the case? Leave it as it is for now but could | ||
| 7046 | likely be removed? | ||
| 7047 | */ | ||
| 7048 |
2/4✓ Branch 0 taken 566 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 566 times.
|
566 | if (check_stack_overrun(thd, 5 * STACK_MIN_SIZE, (uchar *)&new_h2)) |
| 7049 | ✗ | return 1; | |
| 7050 | |||
| 7051 |
2/4✓ Branch 0 taken 566 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 566 times.
|
566 | if (!(new_h2 = h->clone(table->s->normalized_path.str, thd->mem_root))) |
| 7052 | ✗ | return 1; | |
| 7053 | 566 | h2 = new_h2; /* Ok, now can put it into h2 */ | |
| 7054 |
1/2✓ Branch 0 taken 566 times.
✗ Branch 1 not taken.
|
566 | table->prepare_for_position(); |
| 7055 | } | ||
| 7056 | |||
| 7057 | /* | ||
| 7058 | Open the index scan on h2 using the key from the primary handler. | ||
| 7059 | */ | ||
| 7060 |
2/2✓ Branch 0 taken 10060633 times.
✓ Branch 1 taken 4398 times.
|
10065031 | if (h2->active_index == MAX_KEY) { |
| 7061 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10060633 times.
|
10060633 | assert(h->active_index != MAX_KEY); |
| 7062 | 10060633 | const uint mrr_keyno = h->active_index; | |
| 7063 | |||
| 7064 |
2/4✓ Branch 0 taken 10060633 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10060633 times.
|
10060633 | if ((retval = h2->ha_external_lock(thd, h->get_lock_type()))) goto error; |
| 7065 | |||
| 7066 |
2/4✓ Branch 0 taken 10060633 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10060633 times.
|
10060633 | if ((retval = h2->extra(HA_EXTRA_KEYREAD))) goto error; |
| 7067 | |||
| 7068 |
2/4✓ Branch 0 taken 10060633 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10060633 times.
|
10060633 | if ((retval = h2->ha_index_init(mrr_keyno, false))) goto error; |
| 7069 | |||
| 7070 |
3/4✓ Branch 0 taken 53 times.
✓ Branch 1 taken 10060580 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10060633 times.
|
10060686 | if ((table->key_info[mrr_keyno].flags & HA_MULTI_VALUED_KEY) && |
| 7071 |
2/4✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 53 times.
|
53 | (retval = h2->ha_extra(HA_EXTRA_ENABLE_UNIQUE_RECORD_FILTER))) |
| 7072 | ✗ | goto error; /* purecov: inspected */ | |
| 7073 | |||
| 7074 | // Transfer ICP from h to h2 | ||
| 7075 |
2/2✓ Branch 0 taken 232 times.
✓ Branch 1 taken 10060401 times.
|
10060633 | if (mrr_keyno == h->pushed_idx_cond_keyno) { |
| 7076 |
2/4✓ Branch 0 taken 232 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 232 times.
|
232 | if (h2->idx_cond_push(mrr_keyno, h->pushed_idx_cond)) { |
| 7077 | ✗ | retval = 1; | |
| 7078 | ✗ | goto error; | |
| 7079 | } | ||
| 7080 | } else { | ||
| 7081 | // Cancel any potentially previously pushed index conditions | ||
| 7082 |
1/2✓ Branch 0 taken 10060396 times.
✗ Branch 1 not taken.
|
10060401 | h2->cancel_pushed_idx_cond(); |
| 7083 | } | ||
| 7084 | } else { | ||
| 7085 | /* | ||
| 7086 | h2 has already an open index. This happens when the DS-MRR scan | ||
| 7087 | is re-started without closing it first. In this case the primary | ||
| 7088 | handler must be used for reading records from the table, ie. it | ||
| 7089 | must not be opened for doing a new range scan. In this case | ||
| 7090 | the active_index must either not be set or be the primary key. | ||
| 7091 | */ | ||
| 7092 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4398 times.
|
4398 | assert(h->inited == handler::RND); |
| 7093 |
3/4✓ Branch 0 taken 4360 times.
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4360 times.
|
4398 | assert(h->active_index == MAX_KEY || |
| 7094 | h->active_index == table->s->primary_key); | ||
| 7095 | } | ||
| 7096 | |||
| 7097 | /* | ||
| 7098 | The index scan is now transferred to h2 and we can close the open | ||
| 7099 | index scan on the primary handler. | ||
| 7100 | */ | ||
| 7101 |
2/2✓ Branch 0 taken 10060633 times.
✓ Branch 1 taken 4393 times.
|
10065026 | if (h->inited == handler::INDEX) { |
| 7102 | /* | ||
| 7103 | Calling h->ha_index_end() will invoke dsmrr_close() for this object, | ||
| 7104 | which will close the index scan on h2. We need to keep it open, so | ||
| 7105 | temporarily move h2 out of the DsMrr object. | ||
| 7106 | */ | ||
| 7107 | 10060633 | handler *save_h2 = h2; | |
| 7108 | 10060633 | h2 = nullptr; | |
| 7109 |
1/2✓ Branch 0 taken 10060633 times.
✗ Branch 1 not taken.
|
10060633 | retval = h->ha_index_end(); |
| 7110 | 10060633 | h2 = save_h2; | |
| 7111 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10060633 times.
|
10060633 | if (retval) goto error; |
| 7112 | } | ||
| 7113 | |||
| 7114 | /* | ||
| 7115 | Verify consistency between h and h2. | ||
| 7116 | */ | ||
| 7117 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10065026 times.
|
10065026 | assert(h->inited != handler::INDEX); |
| 7118 |
3/4✓ Branch 0 taken 4360 times.
✓ Branch 1 taken 10060666 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4360 times.
|
10065026 | assert(h->active_index == MAX_KEY || |
| 7119 | h->active_index == table->s->primary_key); | ||
| 7120 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10065026 times.
|
10065026 | assert(h2->inited == handler::INDEX); |
| 7121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10065026 times.
|
10065026 | assert(h2->active_index != MAX_KEY); |
| 7122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10065026 times.
|
10065026 | assert(h->get_lock_type() == h2->get_lock_type()); |
| 7123 | |||
| 7124 |
2/4✓ Branch 0 taken 10065026 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10065026 times.
|
10065026 | if ((retval = h2->handler::multi_range_read_init(seq_funcs, seq_init_param, |
| 7125 | n_ranges, mode, buf))) | ||
| 7126 | ✗ | goto error; | |
| 7127 | |||
| 7128 |
3/4✓ Branch 0 taken 10065026 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10065025 times.
|
10065026 | if ((retval = dsmrr_fill_buffer())) goto error; |
| 7129 | |||
| 7130 | /* | ||
| 7131 | If the above call has scanned through all intervals in *seq, then | ||
| 7132 | adjust *buf to indicate that the remaining buffer space will not be used. | ||
| 7133 | */ | ||
| 7134 |
2/2✓ Branch 0 taken 10064920 times.
✓ Branch 1 taken 105 times.
|
10065025 | if (dsmrr_eof) buf->end_of_used_area = rowids_buf_last; |
| 7135 | |||
| 7136 | /* | ||
| 7137 | h->inited == INDEX may occur when 'range checked for each record' is | ||
| 7138 | used. | ||
| 7139 | */ | ||
| 7140 |
4/6✓ Branch 0 taken 10060632 times.
✓ Branch 1 taken 4393 times.
✓ Branch 2 taken 10060632 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10065025 times.
|
30186289 | if ((h->inited != handler::RND) && |
| 7141 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 10060632 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
10060632 | ((h->inited == handler::INDEX ? h->ha_index_end() : false) || |
| 7142 |
2/4✓ Branch 0 taken 10060632 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10060632 times.
|
10060632 | (h->ha_rnd_init(false)))) { |
| 7143 | ✗ | retval = 1; | |
| 7144 | ✗ | goto error; | |
| 7145 | } | ||
| 7146 | |||
| 7147 | 10065025 | use_default_impl = false; | |
| 7148 | 10065025 | h->mrr_funcs = *seq_funcs; | |
| 7149 | |||
| 7150 | 10065025 | return 0; | |
| 7151 | 1 | error: | |
| 7152 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | h2->ha_index_or_rnd_end(); |
| 7153 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | h2->ha_external_lock(thd, F_UNLCK); |
| 7154 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | h2->ha_close(); |
| 7155 | 1 | destroy(h2); | |
| 7156 | 1 | h2 = nullptr; | |
| 7157 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(retval != 0); |
| 7158 | 1 | return retval; | |
| 7159 | 10725729 | } | |
| 7160 | |||
| 7161 | 135737092 | void DsMrr_impl::dsmrr_close() { | |
| 7162 |
1/2✓ Branch 0 taken 135737125 times.
✗ Branch 1 not taken.
|
135737092 | DBUG_TRACE; |
| 7163 | |||
| 7164 | // If there is an open index on h2, then close it | ||
| 7165 |
4/4✓ Branch 0 taken 10061224 times.
✓ Branch 1 taken 125675901 times.
✓ Branch 2 taken 10060632 times.
✓ Branch 3 taken 592 times.
|
135737125 | if (h2 && h2->active_index != MAX_KEY) { |
| 7166 |
1/2✓ Branch 0 taken 10060632 times.
✗ Branch 1 not taken.
|
10060632 | h2->ha_index_or_rnd_end(); |
| 7167 |
2/4✓ Branch 0 taken 10060632 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10060632 times.
✗ Branch 3 not taken.
|
10060632 | h2->ha_external_lock(current_thd, F_UNLCK); |
| 7168 | } | ||
| 7169 | 135737125 | use_default_impl = true; | |
| 7170 | 135737125 | } | |
| 7171 | |||
| 7172 | 107847171 | void DsMrr_impl::reset() { | |
| 7173 |
1/2✓ Branch 0 taken 107850239 times.
✗ Branch 1 not taken.
|
107847171 | DBUG_TRACE; |
| 7174 | |||
| 7175 |
2/2✓ Branch 0 taken 565 times.
✓ Branch 1 taken 107849674 times.
|
107850239 | if (h2) { |
| 7176 | // Close any ongoing DS-MRR scan | ||
| 7177 |
1/2✓ Branch 0 taken 565 times.
✗ Branch 1 not taken.
|
565 | dsmrr_close(); |
| 7178 | |||
| 7179 | // Close and delete the h2 handler | ||
| 7180 |
1/2✓ Branch 0 taken 565 times.
✗ Branch 1 not taken.
|
565 | h2->ha_close(); |
| 7181 | 565 | destroy(h2); | |
| 7182 | 565 | h2 = nullptr; | |
| 7183 | } | ||
| 7184 | 107850239 | } | |
| 7185 | |||
| 7186 | /** | ||
| 7187 | DS-MRR: Fill the buffer with rowids and sort it by rowid | ||
| 7188 | |||
| 7189 | {This is an internal function of DiskSweep MRR implementation} | ||
| 7190 | Scan the MRR ranges and collect ROWIDs (or {ROWID, range_id} pairs) into | ||
| 7191 | buffer. When the buffer is full or scan is completed, sort the buffer by | ||
| 7192 | rowid and return. | ||
| 7193 | |||
| 7194 | The function assumes that rowids buffer is empty when it is invoked. | ||
| 7195 | |||
| 7196 | @retval 0 OK, the next portion of rowids is in the buffer, | ||
| 7197 | properly ordered | ||
| 7198 | @retval other Error | ||
| 7199 | */ | ||
| 7200 | |||
| 7201 | 10065425 | int DsMrr_impl::dsmrr_fill_buffer() { | |
| 7202 | char *range_info; | ||
| 7203 | 10065425 | int res = 0; | |
| 7204 |
1/2✓ Branch 0 taken 10065425 times.
✗ Branch 1 not taken.
|
10065425 | DBUG_TRACE; |
| 7205 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10065425 times.
|
10065425 | assert(rowids_buf < rowids_buf_end); |
| 7206 | |||
| 7207 | /* | ||
| 7208 | Set key_read to true since we only read fields from the index. | ||
| 7209 | This ensures that any virtual columns are read from index and are not | ||
| 7210 | attempted to be evaluated from base columns. | ||
| 7211 | (Do not use TABLE::set_keyread() since the MRR implementation operates | ||
| 7212 | with two handler objects, and set_keyread() would manipulate the keyread | ||
| 7213 | property of the wrong handler. MRR sets the handlers' keyread properties | ||
| 7214 | when initializing the MRR operation, independent of this call). | ||
| 7215 | */ | ||
| 7216 | 10065425 | bool table_keyread_save = table->key_read; | |
| 7217 | 10065425 | table->key_read = true; | |
| 7218 | |||
| 7219 | 10065425 | rowids_buf_cur = rowids_buf; | |
| 7220 | /* | ||
| 7221 | Do not use ha_multi_range_read_next() as it would call the engine's | ||
| 7222 | overridden multi_range_read_next() but the default implementation is wanted. | ||
| 7223 | */ | ||
| 7224 |
4/4✓ Branch 0 taken 10086873 times.
✓ Branch 1 taken 399 times.
✓ Branch 2 taken 21847 times.
✓ Branch 3 taken 10065425 times.
|
20174145 | while ((rowids_buf_cur < rowids_buf_end) && |
| 7225 |
3/4✓ Branch 0 taken 10086873 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21847 times.
✓ Branch 3 taken 10065026 times.
|
10086873 | !(res = h2->handler::multi_range_read_next(&range_info))) { |
| 7226 | /* Put rowid, or {rowid, range_id} pair into the buffer */ | ||
| 7227 |
1/2✓ Branch 0 taken 21847 times.
✗ Branch 1 not taken.
|
21847 | h2->position(table->record[0]); |
| 7228 | 21847 | memcpy(rowids_buf_cur, h2->ref, h2->ref_length); | |
| 7229 | 21847 | rowids_buf_cur += h2->ref_length; | |
| 7230 | |||
| 7231 |
2/2✓ Branch 0 taken 17542 times.
✓ Branch 1 taken 4305 times.
|
21847 | if (is_mrr_assoc) { |
| 7232 | 17542 | memcpy(rowids_buf_cur, &range_info, sizeof(void *)); | |
| 7233 | 17542 | rowids_buf_cur += sizeof(void *); | |
| 7234 | } | ||
| 7235 | } | ||
| 7236 | |||
| 7237 | // Restore key_read since the next read operation might read complete rows | ||
| 7238 | 10065425 | table->key_read = table_keyread_save; | |
| 7239 | |||
| 7240 |
4/4✓ Branch 0 taken 10065026 times.
✓ Branch 1 taken 399 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10065025 times.
|
10065425 | if (res && res != HA_ERR_END_OF_FILE) return res; |
| 7241 | 10065424 | dsmrr_eof = (res == HA_ERR_END_OF_FILE); | |
| 7242 | |||
| 7243 | /* Sort the buffer contents by rowid */ | ||
| 7244 | 10065424 | uint elem_size = h->ref_length + (int)is_mrr_assoc * sizeof(void *); | |
| 7245 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10065424 times.
|
10065424 | assert((rowids_buf_cur - rowids_buf) % elem_size == 0); |
| 7246 | |||
| 7247 |
1/2✓ Branch 0 taken 10065424 times.
✗ Branch 1 not taken.
|
10065424 | varlen_sort( |
| 7248 | rowids_buf, rowids_buf_cur, elem_size, | ||
| 7249 | 148170 | [this](const uchar *a, const uchar *b) { return h->cmp_ref(a, b) < 0; }); | |
| 7250 | 10065424 | rowids_buf_last = rowids_buf_cur; | |
| 7251 | 10065424 | rowids_buf_cur = rowids_buf; | |
| 7252 | 10065424 | return 0; | |
| 7253 | 10065425 | } | |
| 7254 | |||
| 7255 | /* | ||
| 7256 | DS-MRR implementation: multi_range_read_next() function | ||
| 7257 | */ | ||
| 7258 | |||
| 7259 | 13867758 | int DsMrr_impl::dsmrr_next(char **range_info) { | |
| 7260 | int res; | ||
| 7261 | 13867758 | uchar *cur_range_info = nullptr; | |
| 7262 | uchar *rowid; | ||
| 7263 | |||
| 7264 |
3/4✓ Branch 0 taken 3781093 times.
✓ Branch 1 taken 10086665 times.
✓ Branch 2 taken 3781170 times.
✗ Branch 3 not taken.
|
13867758 | if (use_default_impl) return h->handler::multi_range_read_next(range_info); |
| 7265 | |||
| 7266 | do { | ||
| 7267 |
2/2✓ Branch 0 taken 10065397 times.
✓ Branch 1 taken 21384 times.
|
10086781 | if (rowids_buf_cur == rowids_buf_last) { |
| 7268 |
2/2✓ Branch 0 taken 10064998 times.
✓ Branch 1 taken 399 times.
|
10065397 | if (dsmrr_eof) { |
| 7269 | 10064998 | res = HA_ERR_END_OF_FILE; | |
| 7270 | 10064998 | goto end; | |
| 7271 | } | ||
| 7272 | |||
| 7273 |
1/2✓ Branch 0 taken 399 times.
✗ Branch 1 not taken.
|
399 | res = dsmrr_fill_buffer(); |
| 7274 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 399 times.
|
399 | if (res) goto end; |
| 7275 | } | ||
| 7276 | |||
| 7277 | /* return eof if there are no rowids in the buffer after re-fill attempt */ | ||
| 7278 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 21775 times.
|
21783 | if (rowids_buf_cur == rowids_buf_last) { |
| 7279 | 8 | res = HA_ERR_END_OF_FILE; | |
| 7280 | 8 | goto end; | |
| 7281 | } | ||
| 7282 | 21775 | rowid = rowids_buf_cur; | |
| 7283 | |||
| 7284 |
2/2✓ Branch 0 taken 17470 times.
✓ Branch 1 taken 4305 times.
|
21775 | if (is_mrr_assoc) |
| 7285 | 17470 | memcpy(&cur_range_info, rowids_buf_cur + h->ref_length, sizeof(uchar *)); | |
| 7286 | |||
| 7287 | 21775 | rowids_buf_cur += h->ref_length + sizeof(void *) * is_mrr_assoc; | |
| 7288 |
4/4✓ Branch 0 taken 169 times.
✓ Branch 1 taken 21606 times.
✓ Branch 2 taken 116 times.
✓ Branch 3 taken 21659 times.
|
21944 | if (h2->mrr_funcs.skip_record && |
| 7289 |
3/4✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✓ Branch 3 taken 79 times.
|
169 | h2->mrr_funcs.skip_record(h2->mrr_iter, (char *)cur_range_info, rowid)) |
| 7290 | 116 | continue; | |
| 7291 |
1/2✓ Branch 0 taken 21685 times.
✗ Branch 1 not taken.
|
21659 | res = h->ha_rnd_pos(table->record[0], rowid); |
| 7292 | 21685 | break; | |
| 7293 | } while (true); | ||
| 7294 | |||
| 7295 |
2/2✓ Branch 0 taken 4305 times.
✓ Branch 1 taken 17380 times.
|
21685 | if (is_mrr_assoc) { |
| 7296 | 17380 | memcpy(range_info, rowid + h->ref_length, sizeof(void *)); | |
| 7297 | } | ||
| 7298 | 4305 | end: | |
| 7299 | 10086691 | return res; | |
| 7300 | } | ||
| 7301 | |||
| 7302 | /* | ||
| 7303 | DS-MRR implementation: multi_range_read_info() function | ||
| 7304 | */ | ||
| 7305 | 4108 | ha_rows DsMrr_impl::dsmrr_info(uint keyno, uint n_ranges, uint rows, | |
| 7306 | uint *bufsz, uint *flags, Cost_estimate *cost) { | ||
| 7307 | ha_rows res [[maybe_unused]]; | ||
| 7308 | 4108 | uint def_flags = *flags; | |
| 7309 | 4108 | uint def_bufsz = *bufsz; | |
| 7310 | |||
| 7311 | /* Get cost/flags/mem_usage of default MRR implementation */ | ||
| 7312 |
1/2✓ Branch 0 taken 4108 times.
✗ Branch 1 not taken.
|
4108 | res = h->handler::multi_range_read_info(keyno, n_ranges, rows, &def_bufsz, |
| 7313 | &def_flags, cost); | ||
| 7314 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4108 times.
|
4108 | assert(!res); |
| 7315 | |||
| 7316 |
3/4✓ Branch 0 taken 4108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3550 times.
✓ Branch 3 taken 558 times.
|
8216 | if ((*flags & HA_MRR_USE_DEFAULT_IMPL) || |
| 7317 |
3/4✓ Branch 0 taken 4108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3550 times.
✓ Branch 3 taken 558 times.
|
4108 | choose_mrr_impl(keyno, rows, flags, bufsz, cost)) { |
| 7318 | /* Default implementation is chosen */ | ||
| 7319 |
3/8✓ Branch 0 taken 3550 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3550 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3550 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
3550 | DBUG_PRINT("info", ("Default MRR implementation choosen")); |
| 7320 | 3550 | *flags = def_flags; | |
| 7321 | 3550 | *bufsz = def_bufsz; | |
| 7322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3550 times.
|
3550 | assert(*flags & HA_MRR_USE_DEFAULT_IMPL); |
| 7323 | } else { | ||
| 7324 | /* *flags and *bufsz were set by choose_mrr_impl */ | ||
| 7325 |
3/8✓ Branch 0 taken 558 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 558 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 558 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
558 | DBUG_PRINT("info", ("DS-MRR implementation choosen")); |
| 7326 | } | ||
| 7327 | 4108 | return 0; | |
| 7328 | } | ||
| 7329 | |||
| 7330 | /* | ||
| 7331 | DS-MRR Implementation: multi_range_read_info_const() function | ||
| 7332 | */ | ||
| 7333 | |||
| 7334 | 10710006 | ha_rows DsMrr_impl::dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq, | |
| 7335 | void *seq_init_param, uint n_ranges, | ||
| 7336 | uint *bufsz, uint *flags, | ||
| 7337 | Cost_estimate *cost) { | ||
| 7338 | ha_rows rows; | ||
| 7339 | 10710006 | uint def_flags = *flags; | |
| 7340 | 10710006 | uint def_bufsz = *bufsz; | |
| 7341 | /* Get cost/flags/mem_usage of default MRR implementation */ | ||
| 7342 |
1/2✓ Branch 0 taken 10710125 times.
✗ Branch 1 not taken.
|
10710006 | rows = h->handler::multi_range_read_info_const( |
| 7343 | keyno, seq, seq_init_param, n_ranges, &def_bufsz, &def_flags, cost); | ||
| 7344 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 10710105 times.
|
10710125 | if (rows == HA_POS_ERROR) { |
| 7345 | /* Default implementation can't perform MRR scan => we can't either */ | ||
| 7346 | 20 | return rows; | |
| 7347 | } | ||
| 7348 | |||
| 7349 | /* | ||
| 7350 | If HA_MRR_USE_DEFAULT_IMPL has been passed to us, that is an order to | ||
| 7351 | use the default MRR implementation (we need it for UPDATE/DELETE). | ||
| 7352 | Otherwise, make a choice based on cost and mrr* flags of | ||
| 7353 | @@optimizer_switch. | ||
| 7354 | */ | ||
| 7355 |
4/4✓ Branch 0 taken 10709726 times.
✓ Branch 1 taken 379 times.
✓ Branch 2 taken 647919 times.
✓ Branch 3 taken 10062232 times.
|
21419877 | if ((*flags & HA_MRR_USE_DEFAULT_IMPL) || |
| 7356 |
3/4✓ Branch 0 taken 10709772 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 647593 times.
✓ Branch 3 taken 10062179 times.
|
10709726 | choose_mrr_impl(keyno, rows, flags, bufsz, cost)) { |
| 7357 |
5/8✓ Branch 0 taken 647930 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 647983 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 647979 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
|
647919 | DBUG_PRINT("info", ("Default MRR implementation choosen")); |
| 7358 | 647983 | *flags = def_flags; | |
| 7359 | 647983 | *bufsz = def_bufsz; | |
| 7360 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 647983 times.
|
647983 | assert(*flags & HA_MRR_USE_DEFAULT_IMPL); |
| 7361 | } else { | ||
| 7362 | /* *flags and *bufsz were set by choose_mrr_impl */ | ||
| 7363 |
3/8✓ Branch 0 taken 10062179 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10062179 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10062179 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
10062232 | DBUG_PRINT("info", ("DS-MRR implementation choosen")); |
| 7364 | } | ||
| 7365 | 10710137 | return rows; | |
| 7366 | } | ||
| 7367 | |||
| 7368 | /** | ||
| 7369 | DS-MRR Internals: Choose between Default MRR implementation and DS-MRR | ||
| 7370 | |||
| 7371 | Make the choice between using Default MRR implementation and DS-MRR. | ||
| 7372 | This function contains common functionality factored out of dsmrr_info() | ||
| 7373 | and dsmrr_info_const(). The function assumes that the default MRR | ||
| 7374 | implementation's applicability requirements are satisfied. | ||
| 7375 | |||
| 7376 | @param keyno Index number | ||
| 7377 | @param rows E(full rows to be retrieved) | ||
| 7378 | @param flags IN MRR flags provided by the MRR user | ||
| 7379 | OUT If DS-MRR is chosen, flags of DS-MRR implementation | ||
| 7380 | else the value is not modified | ||
| 7381 | @param bufsz IN If DS-MRR is chosen, buffer use of DS-MRR implementation | ||
| 7382 | else the value is not modified | ||
| 7383 | @param cost IN Cost of default MRR implementation | ||
| 7384 | OUT If DS-MRR is chosen, cost of DS-MRR scan | ||
| 7385 | else the value is not modified | ||
| 7386 | |||
| 7387 | @retval true Default MRR implementation should be used | ||
| 7388 | @retval false DS-MRR implementation should be used | ||
| 7389 | */ | ||
| 7390 | |||
| 7391 | 10713797 | bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags, | |
| 7392 | uint *bufsz, Cost_estimate *cost) { | ||
| 7393 | bool res; | ||
| 7394 |
1/2✓ Branch 0 taken 10713869 times.
✗ Branch 1 not taken.
|
10713797 | THD *thd = current_thd; |
| 7395 | 10713869 | TABLE_LIST *tl = table->pos_in_table_list; | |
| 7396 | const bool mrr_on = | ||
| 7397 |
1/2✓ Branch 0 taken 10713931 times.
✗ Branch 1 not taken.
|
10713869 | hint_key_state(thd, tl, keyno, MRR_HINT_ENUM, OPTIMIZER_SWITCH_MRR); |
| 7398 | const bool force_dsmrr_by_hints = | ||
| 7399 |
3/4✓ Branch 0 taken 10713972 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10713967 times.
✓ Branch 3 taken 5 times.
|
21427901 | hint_key_state(thd, tl, keyno, MRR_HINT_ENUM, 0) || |
| 7400 |
3/4✓ Branch 0 taken 10713970 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 10713939 times.
|
10713967 | hint_table_state(thd, tl, BKA_HINT_ENUM, 0); |
| 7401 | |||
| 7402 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26114 times.
|
26124 | if (!(mrr_on || force_dsmrr_by_hints) || |
| 7403 |
2/2✓ Branch 0 taken 10276932 times.
✓ Branch 1 taken 410929 times.
|
10687861 | *flags & (HA_MRR_INDEX_ONLY | HA_MRR_SORTED) || // Unsupported by DS-MRR |
| 7404 |
7/8✓ Branch 0 taken 66370 times.
✓ Branch 1 taken 10210562 times.
✓ Branch 2 taken 66370 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 294 times.
✓ Branch 5 taken 66076 times.
✓ Branch 6 taken 10209252 times.
✓ Branch 7 taken 1525 times.
|
20487709 | (keyno == table->s->primary_key && h->primary_key_is_clustered()) || |
| 7405 |
4/4✓ Branch 0 taken 26124 times.
✓ Branch 1 taken 10687851 times.
✓ Branch 2 taken 504665 times.
✓ Branch 3 taken 10209231 times.
|
31638727 | key_uses_partial_cols(table, keyno) || |
| 7406 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 10209245 times.
|
10209252 | table->s->tmp_table != NO_TMP_TABLE) { |
| 7407 | /* Use the default implementation, don't modify args: See comments */ | ||
| 7408 | 504665 | return true; | |
| 7409 | } | ||
| 7410 | |||
| 7411 | /* | ||
| 7412 | If @@optimizer_switch has "mrr_cost_based" on, we should avoid | ||
| 7413 | using DS-MRR for queries where it is likely that the records are | ||
| 7414 | stored in memory. Since there is currently no way to determine | ||
| 7415 | this, we use a heuristic: | ||
| 7416 | a) if the storage engine has a memory buffer, DS-MRR is only | ||
| 7417 | considered if the table size is bigger than the buffer. | ||
| 7418 | b) if the storage engine does not have a memory buffer, DS-MRR is | ||
| 7419 | only considered if the table size is bigger than 100MB. | ||
| 7420 | c) Since there is an initial setup cost of DS-MRR, so it is only | ||
| 7421 | considered if at least 50 records will be read. | ||
| 7422 | */ | ||
| 7423 |
4/4✓ Branch 0 taken 146697 times.
✓ Branch 1 taken 10062548 times.
✓ Branch 2 taken 146681 times.
✓ Branch 3 taken 10062564 times.
|
10355928 | if (thd->optimizer_switch_flag(OPTIMIZER_SWITCH_MRR_COST_BASED) && |
| 7424 |
2/2✓ Branch 0 taken 146681 times.
✓ Branch 1 taken 16 times.
|
146697 | !force_dsmrr_by_hints) { |
| 7425 | /* | ||
| 7426 | If the storage engine has a database buffer we use this as the | ||
| 7427 | minimum size the table should have before considering DS-MRR. | ||
| 7428 | */ | ||
| 7429 |
1/2✓ Branch 0 taken 146681 times.
✗ Branch 1 not taken.
|
146681 | longlong min_file_size = table->file->get_memory_buffer_size(); |
| 7430 |
2/2✓ Branch 0 taken 51314 times.
✓ Branch 1 taken 95367 times.
|
146681 | if (min_file_size == -1) { |
| 7431 | // No estimate for database buffer | ||
| 7432 | 51314 | min_file_size = 100 * 1024 * 1024; // 100 MB | |
| 7433 | } | ||
| 7434 | |||
| 7435 | 146681 | if (table->file->stats.data_file_length < | |
| 7436 |
3/4✓ Branch 0 taken 197 times.
✓ Branch 1 taken 146484 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 197 times.
|
146681 | static_cast<ulonglong>(min_file_size) || |
| 7437 | rows <= 50) | ||
| 7438 | 146484 | return true; // Use the default implementation | |
| 7439 | } | ||
| 7440 | |||
| 7441 | 10062761 | Cost_estimate dsmrr_cost; | |
| 7442 |
3/4✓ Branch 0 taken 10062761 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 10062746 times.
|
10062761 | if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost)) |
| 7443 | 15 | return true; | |
| 7444 | |||
| 7445 | /* | ||
| 7446 | If @@optimizer_switch has "mrr" on and "mrr_cost_based" off, then set cost | ||
| 7447 | of DS-MRR to be minimum of DS-MRR and Default implementations cost. This | ||
| 7448 | allows one to force use of DS-MRR whenever it is applicable without | ||
| 7449 | affecting other cost-based choices. Note that if MRR or BKA hint is | ||
| 7450 | specified, DS-MRR will be used regardless of cost. | ||
| 7451 | */ | ||
| 7452 | const bool force_dsmrr = | ||
| 7453 |
2/2✓ Branch 0 taken 10062709 times.
✓ Branch 1 taken 37 times.
|
20125455 | (force_dsmrr_by_hints || |
| 7454 |
2/2✓ Branch 0 taken 10062512 times.
✓ Branch 1 taken 197 times.
|
10062709 | !thd->optimizer_switch_flag(OPTIMIZER_SWITCH_MRR_COST_BASED)); |
| 7455 | |||
| 7456 |
6/6✓ Branch 0 taken 10062549 times.
✓ Branch 1 taken 197 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 10062499 times.
✓ Branch 4 taken 50 times.
✓ Branch 5 taken 10062696 times.
|
10062746 | if (force_dsmrr && dsmrr_cost.total_cost() > cost->total_cost()) |
| 7457 | 50 | dsmrr_cost = *cost; | |
| 7458 | |||
| 7459 |
6/6✓ Branch 0 taken 197 times.
✓ Branch 1 taken 10062549 times.
✓ Branch 2 taken 188 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 10062737 times.
✓ Branch 5 taken 9 times.
|
10062746 | if (force_dsmrr || (dsmrr_cost.total_cost() <= cost->total_cost())) { |
| 7460 | 10062737 | *flags &= ~HA_MRR_USE_DEFAULT_IMPL; /* Use the DS-MRR implementation */ | |
| 7461 | 10062737 | *flags &= ~HA_MRR_SUPPORT_SORTED; /* We can't provide ordered output */ | |
| 7462 | 10062737 | *cost = dsmrr_cost; | |
| 7463 | 10062737 | res = false; | |
| 7464 | } else { | ||
| 7465 | /* Use the default MRR implementation */ | ||
| 7466 | 9 | res = true; | |
| 7467 | } | ||
| 7468 | 10062746 | return res; | |
| 7469 | } | ||
| 7470 | |||
| 7471 | static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, | ||
| 7472 | Cost_estimate *cost); | ||
| 7473 | |||
| 7474 | /** | ||
| 7475 | Get cost of DS-MRR scan | ||
| 7476 | |||
| 7477 | @param keynr Index to be used | ||
| 7478 | @param rows E(Number of rows to be scanned) | ||
| 7479 | @param flags Scan parameters (HA_MRR_* flags) | ||
| 7480 | @param buffer_size INOUT Buffer size | ||
| 7481 | @param cost OUT The cost | ||
| 7482 | |||
| 7483 | @retval false OK | ||
| 7484 | @retval true Error, DS-MRR cannot be used (the buffer is too small | ||
| 7485 | for even 1 rowid) | ||
| 7486 | */ | ||
| 7487 | |||
| 7488 | 10062761 | bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, | |
| 7489 | uint *buffer_size, | ||
| 7490 | Cost_estimate *cost) { | ||
| 7491 | ha_rows rows_in_last_step; | ||
| 7492 | uint n_full_steps; | ||
| 7493 | |||
| 7494 | 10062761 | const uint elem_size = | |
| 7495 |
2/2✓ Branch 0 taken 558 times.
✓ Branch 1 taken 10062203 times.
|
10062761 | h->ref_length + sizeof(void *) * !(flags & HA_MRR_NO_ASSOCIATION); |
| 7496 | 10062761 | const ha_rows max_buff_entries = *buffer_size / elem_size; | |
| 7497 | |||
| 7498 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 10062746 times.
|
10062761 | if (!max_buff_entries) |
| 7499 | 15 | return true; /* Buffer has not enough space for even 1 rowid */ | |
| 7500 | |||
| 7501 | /* Number of iterations we'll make with full buffer */ | ||
| 7502 | 10062746 | n_full_steps = (uint)floor(rows2double(rows) / max_buff_entries); | |
| 7503 | |||
| 7504 | /* | ||
| 7505 | Get numbers of rows we'll be processing in last iteration, with | ||
| 7506 | non-full buffer | ||
| 7507 | */ | ||
| 7508 | 10062746 | rows_in_last_step = rows % max_buff_entries; | |
| 7509 | |||
| 7510 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10062746 times.
|
10062746 | assert(cost->is_zero()); |
| 7511 | |||
| 7512 |
2/2✓ Branch 0 taken 62 times.
✓ Branch 1 taken 10062684 times.
|
10062746 | if (n_full_steps) { |
| 7513 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | get_sort_and_sweep_cost(table, max_buff_entries, cost); |
| 7514 | 62 | cost->multiply(n_full_steps); | |
| 7515 | } else { | ||
| 7516 | /* | ||
| 7517 | Adjust buffer size since only parts of the buffer will be used: | ||
| 7518 | 1. Adjust record estimate for the last scan to reduce likelihood | ||
| 7519 | of needing more than one scan by adding 20 percent to the | ||
| 7520 | record estimate and by ensuring this is at least 100 records. | ||
| 7521 | 2. If the estimated needed buffer size is lower than suggested by | ||
| 7522 | the caller then set it to the estimated buffer size. | ||
| 7523 | */ | ||
| 7524 | const ha_rows keys_in_buffer = | ||
| 7525 | 10062684 | max<ha_rows>(static_cast<ha_rows>(1.2 * rows_in_last_step), 100); | |
| 7526 | 20125368 | *buffer_size = min<ulong>(*buffer_size, | |
| 7527 | 10062684 | static_cast<ulong>(keys_in_buffer) * elem_size); | |
| 7528 | } | ||
| 7529 | |||
| 7530 | 10062746 | Cost_estimate last_step_cost; | |
| 7531 |
1/2✓ Branch 0 taken 10062746 times.
✗ Branch 1 not taken.
|
10062746 | get_sort_and_sweep_cost(table, rows_in_last_step, &last_step_cost); |
| 7532 | 10062746 | (*cost) += last_step_cost; | |
| 7533 | |||
| 7534 | /* | ||
| 7535 | Cost of memory is not included in the total_cost() function and | ||
| 7536 | thus will not be considered when comparing costs. Still, we | ||
| 7537 | record it in the cost estimate object for future use. | ||
| 7538 | */ | ||
| 7539 | 10062746 | cost->add_mem(*buffer_size); | |
| 7540 | |||
| 7541 | /* Total cost of all index accesses */ | ||
| 7542 |
1/2✓ Branch 0 taken 10062746 times.
✗ Branch 1 not taken.
|
10062746 | (*cost) += h->index_scan_cost(keynr, 1, static_cast<double>(rows)); |
| 7543 | |||
| 7544 | /* | ||
| 7545 | Add CPU cost for processing records (see | ||
| 7546 | @handler::multi_range_read_info_const()). | ||
| 7547 | */ | ||
| 7548 | 10062746 | cost->add_cpu( | |
| 7549 | 10062746 | table->cost_model()->row_evaluate_cost(static_cast<double>(rows))); | |
| 7550 | 10062746 | return false; | |
| 7551 | } | ||
| 7552 | |||
| 7553 | /* | ||
| 7554 | Get cost of one sort-and-sweep step | ||
| 7555 | |||
| 7556 | SYNOPSIS | ||
| 7557 | get_sort_and_sweep_cost() | ||
| 7558 | table Table being accessed | ||
| 7559 | nrows Number of rows to be sorted and retrieved | ||
| 7560 | cost OUT The cost | ||
| 7561 | |||
| 7562 | DESCRIPTION | ||
| 7563 | Get cost of these operations: | ||
| 7564 | - sort an array of #nrows ROWIDs using qsort | ||
| 7565 | - read #nrows records from table in a sweep. | ||
| 7566 | */ | ||
| 7567 | |||
| 7568 | 10062808 | static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows, | |
| 7569 | Cost_estimate *cost) { | ||
| 7570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10062808 times.
|
10062808 | assert(cost->is_zero()); |
| 7571 |
2/2✓ Branch 0 taken 10062794 times.
✓ Branch 1 taken 14 times.
|
10062808 | if (nrows) { |
| 7572 | 10062794 | get_sweep_read_cost(table, nrows, false, cost); | |
| 7573 | |||
| 7574 | /* | ||
| 7575 | @todo CostModel: For the old version of the cost model the | ||
| 7576 | following code should be used. For the new version of the cost | ||
| 7577 | model Cost_model::key_compare_cost() should be used. When | ||
| 7578 | removing support for the old cost model this code should be | ||
| 7579 | removed. The reason for this is that we should get rid of the | ||
| 7580 | ROWID_COMPARE_SORT_COST and use key_compare_cost() instead. For | ||
| 7581 | the current value returned by key_compare_cost() this would | ||
| 7582 | overestimate the cost for sorting. | ||
| 7583 | */ | ||
| 7584 | |||
| 7585 | /* | ||
| 7586 | Constant for the cost of doing one key compare operation in the | ||
| 7587 | sort operation. We should have used the value returned by | ||
| 7588 | key_compare_cost() here but this would make the cost | ||
| 7589 | estimate of sorting very high for queries accessing many | ||
| 7590 | records. Until this constant is adjusted we introduce a constant | ||
| 7591 | that is more realistic. @todo: Replace this with | ||
| 7592 | key_compare_cost() when this has been given a realistic value. | ||
| 7593 | */ | ||
| 7594 | const double ROWID_COMPARE_SORT_COST = | ||
| 7595 | 10062794 | table->cost_model()->key_compare_cost(1.0) / 10; | |
| 7596 | |||
| 7597 | /* Add cost of qsort call: n * log2(n) * cost(rowid_comparison) */ | ||
| 7598 | |||
| 7599 | // For the old version of the cost model this cost calculations should | ||
| 7600 | // be used.... | ||
| 7601 | 10062794 | const double cpu_sort = nrows * log2(nrows) * ROWID_COMPARE_SORT_COST; | |
| 7602 | // .... For the new cost model something like this should be used... | ||
| 7603 | // cpu_sort= nrows * log2(nrows) * | ||
| 7604 | // table->cost_model()->rowid_compare_cost(); | ||
| 7605 | 10062794 | cost->add_cpu(cpu_sort); | |
| 7606 | } | ||
| 7607 | 10062808 | } | |
| 7608 | |||
| 7609 | /** | ||
| 7610 | Get cost of reading nrows table records in a "disk sweep" | ||
| 7611 | |||
| 7612 | A disk sweep read is a sequence of handler->rnd_pos(rowid) calls that made | ||
| 7613 | for an ordered sequence of rowids. | ||
| 7614 | |||
| 7615 | We take into account that some of the records might be in a memory | ||
| 7616 | buffer while others need to be read from a secondary storage | ||
| 7617 | device. The model for this assumes hard disk IO. A disk read is | ||
| 7618 | performed as follows: | ||
| 7619 | |||
| 7620 | 1. The disk head is moved to the needed cylinder | ||
| 7621 | 2. The controller waits for the plate to rotate | ||
| 7622 | 3. The data is transferred | ||
| 7623 | |||
| 7624 | Time to do #3 is insignificant compared to #2+#1. | ||
| 7625 | |||
| 7626 | Time to move the disk head is proportional to head travel distance. | ||
| 7627 | |||
| 7628 | Time to wait for the plate to rotate depends on whether the disk head | ||
| 7629 | was moved or not. | ||
| 7630 | |||
| 7631 | If disk head wasn't moved, the wait time is proportional to distance | ||
| 7632 | between the previous block and the block we're reading. | ||
| 7633 | |||
| 7634 | If the head was moved, we don't know how much we'll need to wait for the | ||
| 7635 | plate to rotate. We assume the wait time to be a variate with a mean of | ||
| 7636 | 0.5 of full rotation time. | ||
| 7637 | |||
| 7638 | Our cost units are "random disk seeks". The cost of random disk seek is | ||
| 7639 | actually not a constant, it depends one range of cylinders we're going | ||
| 7640 | to access. We make it constant by introducing a fuzzy concept of "typical | ||
| 7641 | datafile length" (it's fuzzy as it's hard to tell whether it should | ||
| 7642 | include index file, temp.tables etc). Then random seek cost is: | ||
| 7643 | |||
| 7644 | 1 = half_rotation_cost + move_cost * 1/3 * typical_data_file_length | ||
| 7645 | |||
| 7646 | We define half_rotation_cost as disk_seek_base_cost() (see | ||
| 7647 | Cost_model_server::disk_seek_base_cost()). | ||
| 7648 | |||
| 7649 | @param table Table to be accessed | ||
| 7650 | @param nrows Number of rows to retrieve | ||
| 7651 | @param interrupted true <=> Assume that the disk sweep will be | ||
| 7652 | interrupted by other disk IO. false - otherwise. | ||
| 7653 | @param[out] cost the cost | ||
| 7654 | */ | ||
| 7655 | |||
| 7656 | 10163923 | void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted, | |
| 7657 | Cost_estimate *cost) { | ||
| 7658 |
1/2✓ Branch 0 taken 10163923 times.
✗ Branch 1 not taken.
|
10163923 | DBUG_TRACE; |
| 7659 | |||
| 7660 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10163923 times.
|
10163923 | assert(cost->is_zero()); |
| 7661 |
2/2✓ Branch 0 taken 10163786 times.
✓ Branch 1 taken 137 times.
|
10163923 | if (nrows > 0) { |
| 7662 | 10163786 | const Cost_model_table *const cost_model = table->cost_model(); | |
| 7663 | |||
| 7664 | // The total number of blocks used by this table | ||
| 7665 | double n_blocks = | ||
| 7666 | 10163786 | ceil(ulonglong2double(table->file->stats.data_file_length) / IO_SIZE); | |
| 7667 |
2/2✓ Branch 0 taken 10030020 times.
✓ Branch 1 taken 133766 times.
|
10163786 | if (n_blocks < 1.0) // When data_file_length is 0 |
| 7668 | 10030020 | n_blocks = 1.0; | |
| 7669 | |||
| 7670 | /* | ||
| 7671 | The number of blocks that in average need to be read given that | ||
| 7672 | the records are uniformly distribution over the table. | ||
| 7673 | */ | ||
| 7674 | double busy_blocks = | ||
| 7675 | 10163786 | n_blocks * (1.0 - pow(1.0 - 1.0 / n_blocks, rows2double(nrows))); | |
| 7676 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 10163765 times.
|
10163786 | if (busy_blocks < 1.0) busy_blocks = 1.0; |
| 7677 | |||
| 7678 |
3/8✓ Branch 0 taken 10163786 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10163786 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10163786 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
10163786 | DBUG_PRINT("info", |
| 7679 | ("sweep: nblocks=%g, busy_blocks=%g", n_blocks, busy_blocks)); | ||
| 7680 | /* | ||
| 7681 | The random access cost for reading the data pages will be the upper | ||
| 7682 | limit for the sweep_cost. | ||
| 7683 | */ | ||
| 7684 |
1/2✓ Branch 0 taken 10163786 times.
✗ Branch 1 not taken.
|
10163786 | cost->add_io(cost_model->page_read_cost(busy_blocks)); |
| 7685 |
2/2✓ Branch 0 taken 10064164 times.
✓ Branch 1 taken 99622 times.
|
10163786 | if (!interrupted) { |
| 7686 | 10064164 | Cost_estimate sweep_cost; | |
| 7687 | /* | ||
| 7688 | Assume reading pages from disk is done in one 'sweep'. | ||
| 7689 | |||
| 7690 | The cost model and cost estimate for pages already in a memory | ||
| 7691 | buffer will be different from pages that needed to be read from | ||
| 7692 | disk. Calculate the number of blocks that likely already are | ||
| 7693 | in memory and the number of blocks that need to be read from | ||
| 7694 | disk. | ||
| 7695 | */ | ||
| 7696 | const double busy_blocks_mem = | ||
| 7697 |
1/2✓ Branch 0 taken 10064164 times.
✗ Branch 1 not taken.
|
10064164 | busy_blocks * table->file->table_in_memory_estimate(); |
| 7698 | 10064164 | const double busy_blocks_disk = busy_blocks - busy_blocks_mem; | |
| 7699 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10064164 times.
|
10064164 | assert(busy_blocks_disk >= 0.0); |
| 7700 | |||
| 7701 | // Cost of accessing blocks in main memory buffer | ||
| 7702 | 10064164 | sweep_cost.add_io(cost_model->buffer_block_read_cost(busy_blocks_mem)); | |
| 7703 | |||
| 7704 | // Cost of reading blocks from disk in a 'sweep' | ||
| 7705 | 10064164 | const double seek_distance = | |
| 7706 |
2/2✓ Branch 0 taken 608 times.
✓ Branch 1 taken 10063556 times.
|
10064164 | (busy_blocks_disk > 1.0) ? n_blocks / busy_blocks_disk : n_blocks; |
| 7707 | |||
| 7708 | const double disk_cost = | ||
| 7709 | 10064164 | busy_blocks_disk * cost_model->disk_seek_cost(seek_distance); | |
| 7710 | 10064164 | sweep_cost.add_io(disk_cost); | |
| 7711 | |||
| 7712 | /* | ||
| 7713 | For some cases, ex: when only few blocks need to be read and the | ||
| 7714 | seek distance becomes very large, the sweep cost model can produce | ||
| 7715 | a cost estimate that is larger than the cost of random access. | ||
| 7716 | To handle this case, we use the sweep cost only when it is less | ||
| 7717 | than the random access cost. | ||
| 7718 | */ | ||
| 7719 |
2/2✓ Branch 0 taken 485 times.
✓ Branch 1 taken 10063679 times.
|
10064164 | if (sweep_cost < *cost) *cost = sweep_cost; |
| 7720 | } | ||
| 7721 | } | ||
| 7722 |
3/8✓ Branch 0 taken 10163923 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10163923 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10163923 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
10163923 | DBUG_PRINT("info", ("returning cost=%g", cost->total_cost())); |
| 7723 | 10163923 | } | |
| 7724 | |||
| 7725 | /**************************************************************************** | ||
| 7726 | * DS-MRR implementation ends | ||
| 7727 | ***************************************************************************/ | ||
| 7728 | |||
| 7729 | /** @brief | ||
| 7730 | Read first row between two ranges. | ||
| 7731 | Store ranges for future calls to read_range_next. | ||
| 7732 | |||
| 7733 | @param start_key Start key. Is 0 if no min range | ||
| 7734 | @param end_key End key. Is 0 if no max range | ||
| 7735 | @param eq_range_arg Set to 1 if start_key == end_key | ||
| 7736 | @param sorted Set to 1 if result should be sorted per key | ||
| 7737 | |||
| 7738 | @note | ||
| 7739 | Record is read into table->record[0] | ||
| 7740 | |||
| 7741 | @retval | ||
| 7742 | 0 Found row | ||
| 7743 | @retval | ||
| 7744 | HA_ERR_END_OF_FILE No rows in range | ||
| 7745 | */ | ||
| 7746 | 10560278 | int handler::read_range_first(const key_range *start_key, | |
| 7747 | const key_range *end_key, bool eq_range_arg, | ||
| 7748 | bool sorted [[maybe_unused]]) { | ||
| 7749 | int result; | ||
| 7750 |
1/2✓ Branch 0 taken 10560449 times.
✗ Branch 1 not taken.
|
10560278 | DBUG_TRACE; |
| 7751 | |||
| 7752 | 10560449 | eq_range = eq_range_arg; | |
| 7753 |
1/2✓ Branch 0 taken 10560402 times.
✗ Branch 1 not taken.
|
10560449 | set_end_range(end_key, RANGE_SCAN_ASC); |
| 7754 | |||
| 7755 | 10560402 | range_key_part = table->key_info[active_index].key_part; | |
| 7756 | |||
| 7757 |
2/2✓ Branch 0 taken 4631 times.
✓ Branch 1 taken 10555771 times.
|
10560402 | if (!start_key) // Read first record |
| 7758 |
1/2✓ Branch 0 taken 4631 times.
✗ Branch 1 not taken.
|
4631 | result = ha_index_first(table->record[0]); |
| 7759 | else | ||
| 7760 | 10555856 | result = ha_index_read_map(table->record[0], start_key->key, | |
| 7761 |
1/2✓ Branch 0 taken 10555856 times.
✗ Branch 1 not taken.
|
10555771 | start_key->keypart_map, start_key->flag); |
| 7762 |
2/2✓ Branch 0 taken 10229863 times.
✓ Branch 1 taken 330624 times.
|
10560487 | if (result) |
| 7763 |
2/2✓ Branch 0 taken 2747 times.
✓ Branch 1 taken 10227116 times.
|
10229863 | return (result == HA_ERR_KEY_NOT_FOUND) ? HA_ERR_END_OF_FILE : result; |
| 7764 | |||
| 7765 |
3/4✓ Branch 0 taken 330624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9765 times.
✓ Branch 3 taken 320859 times.
|
330624 | if (compare_key(end_range) > 0) { |
| 7766 | /* | ||
| 7767 | The last read row does not fall in the range. So request | ||
| 7768 | storage engine to release row lock if possible. | ||
| 7769 | */ | ||
| 7770 |
1/2✓ Branch 0 taken 9765 times.
✗ Branch 1 not taken.
|
9765 | unlock_row(); |
| 7771 | 9765 | result = HA_ERR_END_OF_FILE; | |
| 7772 | } | ||
| 7773 | 330624 | return result; | |
| 7774 | 10560487 | } | |
| 7775 | |||
| 7776 | 24526 | int handler::ha_read_range_first(const key_range *start_key, | |
| 7777 | const key_range *end_key, bool eq_range, | ||
| 7778 | bool sorted) { | ||
| 7779 | int result; | ||
| 7780 |
1/2✓ Branch 0 taken 24526 times.
✗ Branch 1 not taken.
|
24526 | DBUG_TRACE; |
| 7781 | |||
| 7782 | // Set status for the need to update generated fields | ||
| 7783 | 24526 | m_update_generated_read_fields = table->has_gcol(); | |
| 7784 | |||
| 7785 |
1/2✓ Branch 0 taken 24526 times.
✗ Branch 1 not taken.
|
24526 | result = read_range_first(start_key, end_key, eq_range, sorted); |
| 7786 |
3/4✓ Branch 0 taken 9003 times.
✓ Branch 1 taken 15523 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9003 times.
|
24526 | if (!result && m_update_generated_read_fields) { |
| 7787 | ✗ | result = | |
| 7788 | ✗ | update_generated_read_fields(table->record[0], table, active_index); | |
| 7789 | ✗ | m_update_generated_read_fields = false; | |
| 7790 | } | ||
| 7791 | 24526 | table->set_row_status_from_handler(result); | |
| 7792 | 24526 | return result; | |
| 7793 | 24526 | } | |
| 7794 | |||
| 7795 | 56209 | int handler::ha_read_range_next() { | |
| 7796 | int result; | ||
| 7797 |
1/2✓ Branch 0 taken 56209 times.
✗ Branch 1 not taken.
|
56209 | DBUG_TRACE; |
| 7798 | |||
| 7799 | // Set status for the need to update generated fields | ||
| 7800 | 56209 | m_update_generated_read_fields = table->has_gcol(); | |
| 7801 | |||
| 7802 |
1/2✓ Branch 0 taken 56209 times.
✗ Branch 1 not taken.
|
56209 | result = read_range_next(); |
| 7803 |
3/4✓ Branch 0 taken 47531 times.
✓ Branch 1 taken 8678 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 47531 times.
|
56209 | if (!result && m_update_generated_read_fields) { |
| 7804 | ✗ | result = | |
| 7805 | ✗ | update_generated_read_fields(table->record[0], table, active_index); | |
| 7806 | ✗ | m_update_generated_read_fields = false; | |
| 7807 | } | ||
| 7808 | 56209 | table->set_row_status_from_handler(result); | |
| 7809 | 56209 | return result; | |
| 7810 | 56209 | } | |
| 7811 | |||
| 7812 | /** @brief | ||
| 7813 | Read next row between two endpoints. | ||
| 7814 | |||
| 7815 | @note | ||
| 7816 | Record is read into table->record[0] | ||
| 7817 | |||
| 7818 | @retval | ||
| 7819 | 0 Found row | ||
| 7820 | @retval | ||
| 7821 | HA_ERR_END_OF_FILE No rows in range | ||
| 7822 | */ | ||
| 7823 | 3358087 | int handler::read_range_next() { | |
| 7824 |
1/2✓ Branch 0 taken 3358087 times.
✗ Branch 1 not taken.
|
3358087 | DBUG_TRACE; |
| 7825 | |||
| 7826 | int result; | ||
| 7827 |
2/2✓ Branch 0 taken 618558 times.
✓ Branch 1 taken 2739529 times.
|
3358087 | if (eq_range) { |
| 7828 | /* We trust that index_next_same always gives a row in range */ | ||
| 7829 | result = | ||
| 7830 |
1/2✓ Branch 0 taken 618558 times.
✗ Branch 1 not taken.
|
618558 | ha_index_next_same(table->record[0], end_range->key, end_range->length); |
| 7831 | } else { | ||
| 7832 |
1/2✓ Branch 0 taken 2739529 times.
✗ Branch 1 not taken.
|
2739529 | result = ha_index_next(table->record[0]); |
| 7833 |
2/2✓ Branch 0 taken 8716 times.
✓ Branch 1 taken 2730813 times.
|
2739529 | if (result) return result; |
| 7834 | |||
| 7835 |
3/4✓ Branch 0 taken 2730813 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6154 times.
✓ Branch 3 taken 2724659 times.
|
2730813 | if (compare_key(end_range) > 0) { |
| 7836 | /* | ||
| 7837 | The last read row does not fall in the range. So request | ||
| 7838 | storage engine to release row lock if possible. | ||
| 7839 | */ | ||
| 7840 |
1/2✓ Branch 0 taken 6154 times.
✗ Branch 1 not taken.
|
6154 | unlock_row(); |
| 7841 | 6154 | result = HA_ERR_END_OF_FILE; | |
| 7842 | } | ||
| 7843 | } | ||
| 7844 | 3349371 | return result; | |
| 7845 | 3358087 | } | |
| 7846 | |||
| 7847 | /** | ||
| 7848 | Check if one of the columns in a key is a virtual generated column. | ||
| 7849 | |||
| 7850 | @param part the first part of the key to check | ||
| 7851 | @param length the length of the key | ||
| 7852 | @retval true if the key contains a virtual generated column | ||
| 7853 | @retval false if the key does not contain a virtual generated column | ||
| 7854 | */ | ||
| 7855 | 420632 | static bool key_has_vcol(const KEY_PART_INFO *part, uint length) { | |
| 7856 |
2/2✓ Branch 0 taken 501803 times.
✓ Branch 1 taken 420370 times.
|
922173 | for (uint len = 0; len < length; len += part->store_length, ++part) |
| 7857 |
2/2✓ Branch 0 taken 253 times.
✓ Branch 1 taken 501541 times.
|
501803 | if (part->field->is_virtual_gcol()) return true; |
| 7858 | 420370 | return false; | |
| 7859 | } | ||
| 7860 | |||
| 7861 | 10616870 | void handler::set_end_range(const key_range *range, | |
| 7862 | enum_range_scan_direction direction) { | ||
| 7863 |
2/2✓ Branch 0 taken 420625 times.
✓ Branch 1 taken 10196245 times.
|
10616870 | if (range) { |
| 7864 | 420625 | save_end_range = *range; | |
| 7865 | 420625 | end_range = &save_end_range; | |
| 7866 | 420625 | range_key_part = table->key_info[active_index].key_part; | |
| 7867 | 420625 | key_compare_result_on_equal = | |
| 7868 | 420625 | (range->flag == HA_READ_BEFORE_KEY) | |
| 7869 |
2/2✓ Branch 0 taken 413257 times.
✓ Branch 1 taken 7368 times.
|
833882 | ? 1 |
| 7870 |
2/2✓ Branch 0 taken 413172 times.
✓ Branch 1 taken 85 times.
|
413257 | : (range->flag == HA_READ_AFTER_KEY ? -1 : 0); |
| 7871 | 420625 | m_virt_gcol_in_end_range = key_has_vcol(range_key_part, range->length); | |
| 7872 | } else | ||
| 7873 | 10196245 | end_range = nullptr; | |
| 7874 | |||
| 7875 | /* | ||
| 7876 | Clear the out-of-range flag in the record buffer when a new range is | ||
| 7877 | started. Also set the in_range_check_pushed_down flag, since the | ||
| 7878 | storage engine needs to do the evaluation of the end-range to avoid | ||
| 7879 | filling the record buffer with out-of-range records. | ||
| 7880 | */ | ||
| 7881 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 10616802 times.
|
10616898 | if (m_record_buffer != nullptr) { |
| 7882 | 96 | m_record_buffer->set_out_of_range(false); | |
| 7883 | 96 | in_range_check_pushed_down = true; | |
| 7884 | } | ||
| 7885 | |||
| 7886 | 10616898 | range_scan_direction = direction; | |
| 7887 | 10616898 | } | |
| 7888 | |||
| 7889 | /** | ||
| 7890 | Compare if found key (in row) is over max-value. | ||
| 7891 | |||
| 7892 | @param range range to compare to row. May be 0 for no range | ||
| 7893 | |||
| 7894 | @sa | ||
| 7895 | key.cc::key_cmp() | ||
| 7896 | |||
| 7897 | @return | ||
| 7898 | The return value is SIGN(key_in_row - range_key): | ||
| 7899 | |||
| 7900 | - 0 : Key is equal to range or 'range' == 0 (no range) | ||
| 7901 | - -1 : Key is less than range | ||
| 7902 | - 1 : Key is larger than range | ||
| 7903 | */ | ||
| 7904 | 3105351 | int handler::compare_key(key_range *range) { | |
| 7905 | int cmp; | ||
| 7906 |
4/4✓ Branch 0 taken 1153398 times.
✓ Branch 1 taken 1951953 times.
✓ Branch 2 taken 5824 times.
✓ Branch 3 taken 1147574 times.
|
3105351 | if (!range || in_range_check_pushed_down) return 0; // No max range |
| 7907 | 1147574 | cmp = key_cmp(range_key_part, range->key, range->length); | |
| 7908 |
2/2✓ Branch 0 taken 366446 times.
✓ Branch 1 taken 781128 times.
|
1147574 | if (!cmp) cmp = key_compare_result_on_equal; |
| 7909 | 1147574 | return cmp; | |
| 7910 | } | ||
| 7911 | |||
| 7912 | /* | ||
| 7913 | Compare if a found key (in row) is within the range. | ||
| 7914 | |||
| 7915 | This function is similar to compare_key() but checks the range scan | ||
| 7916 | direction to determine if this is a descending scan. This function | ||
| 7917 | is used by the index condition pushdown implementation to determine | ||
| 7918 | if the read record is within the range scan. | ||
| 7919 | |||
| 7920 | @param range Range to compare to row. May be NULL for no range. | ||
| 7921 | |||
| 7922 | @seealso | ||
| 7923 | handler::compare_key() | ||
| 7924 | |||
| 7925 | @return Returns whether the key is within the range | ||
| 7926 | |||
| 7927 | - 0 : Key is equal to range or 'range' == 0 (no range) | ||
| 7928 | - -1 : Key is within the current range | ||
| 7929 | - 1 : Key is outside the current range | ||
| 7930 | */ | ||
| 7931 | |||
| 7932 | 9356 | int handler::compare_key_icp(const key_range *range) const { | |
| 7933 | int cmp; | ||
| 7934 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9356 times.
|
9356 | if (!range) return 0; // no max range |
| 7935 | 9356 | cmp = key_cmp(range_key_part, range->key, range->length); | |
| 7936 |
2/2✓ Branch 0 taken 2542 times.
✓ Branch 1 taken 6814 times.
|
9356 | if (!cmp) cmp = key_compare_result_on_equal; |
| 7937 |
2/2✓ Branch 0 taken 688 times.
✓ Branch 1 taken 8668 times.
|
9356 | if (range_scan_direction == RANGE_SCAN_DESC) cmp = -cmp; |
| 7938 | 9356 | return cmp; | |
| 7939 | } | ||
| 7940 | |||
| 7941 | /** | ||
| 7942 | Change the offsets of all the fields in a key range. | ||
| 7943 | |||
| 7944 | @param range the key range | ||
| 7945 | @param key_part the first key part | ||
| 7946 | @param diff how much to change the offsets with | ||
| 7947 | */ | ||
| 7948 | 6 | static inline void move_key_field_offsets(const key_range *range, | |
| 7949 | const KEY_PART_INFO *key_part, | ||
| 7950 | ptrdiff_t diff) { | ||
| 7951 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | for (size_t len = 0; len < range->length; |
| 7952 | 6 | len += key_part->store_length, ++key_part) | |
| 7953 | 6 | key_part->field->move_field_offset(diff); | |
| 7954 | 6 | } | |
| 7955 | |||
| 7956 | /** | ||
| 7957 | Check if the key in the given buffer (which is not necessarily | ||
| 7958 | TABLE::record[0]) is within range. Called by the storage engine to | ||
| 7959 | avoid reading too many rows. | ||
| 7960 | |||
| 7961 | @param buf the buffer that holds the key | ||
| 7962 | @retval -1 if the key is within the range | ||
| 7963 | @retval 0 if the key is equal to the end_range key, and | ||
| 7964 | key_compare_result_on_equal is 0 | ||
| 7965 | @retval 1 if the key is outside the range | ||
| 7966 | */ | ||
| 7967 | 3 | int handler::compare_key_in_buffer(const uchar *buf) const { | |
| 7968 |
2/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
3 | assert(end_range != nullptr && |
| 7969 | (m_record_buffer == nullptr || !m_record_buffer->is_out_of_range())); | ||
| 7970 | |||
| 7971 | // Make the fields in the key point into the buffer instead of record[0]. | ||
| 7972 | 3 | const ptrdiff_t diff = buf - table->record[0]; | |
| 7973 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (diff != 0) move_key_field_offsets(end_range, range_key_part, diff); |
| 7974 | |||
| 7975 | // Compare the key in buf against end_range. | ||
| 7976 | 3 | int cmp = key_cmp(range_key_part, end_range->key, end_range->length); | |
| 7977 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (cmp == 0) cmp = key_compare_result_on_equal; |
| 7978 | |||
| 7979 | // Reset the field offsets. | ||
| 7980 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (diff != 0) move_key_field_offsets(end_range, range_key_part, -diff); |
| 7981 | |||
| 7982 | // This change is necessary for MyRocks PS-7116. | ||
| 7983 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (range_scan_direction == RANGE_SCAN_DESC) cmp = -cmp; |
| 7984 | |||
| 7985 | 3 | return cmp; | |
| 7986 | } | ||
| 7987 | |||
| 7988 | 50798696 | int handler::index_read_idx_map(uchar *buf, uint index, const uchar *key, | |
| 7989 | key_part_map keypart_map, | ||
| 7990 | enum ha_rkey_function find_flag) { | ||
| 7991 | 50798696 | int error, error1 = 0; | |
| 7992 | 50798696 | error = index_init(index, false); | |
| 7993 |
1/2✓ Branch 0 taken 50799279 times.
✗ Branch 1 not taken.
|
50799277 | if (!error) { |
| 7994 | 50799279 | error = index_read_map(buf, key, keypart_map, find_flag); | |
| 7995 | 50799293 | error1 = index_end(); | |
| 7996 | } | ||
| 7997 |
2/2✓ Branch 0 taken 17754516 times.
✓ Branch 1 taken 33044787 times.
|
50799303 | return error ? error : error1; |
| 7998 | } | ||
| 7999 | |||
| 8000 | 76103955 | uint calculate_key_len(TABLE *table, uint key, key_part_map keypart_map, | |
| 8001 | uint *count) { | ||
| 8002 | /* works only with key prefixes */ | ||
| 8003 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76103955 times.
|
76103955 | assert(((keypart_map + 1) & keypart_map) == 0); |
| 8004 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76103955 times.
|
76103955 | if (count) *count = 0; |
| 8005 | |||
| 8006 | 76103955 | KEY *key_info = table->key_info + key; | |
| 8007 | 76103955 | KEY_PART_INFO *key_part = key_info->key_part; | |
| 8008 | 76103955 | KEY_PART_INFO *end_key_part = key_part + actual_key_parts(key_info); | |
| 8009 | 76104407 | uint length = 0; | |
| 8010 | |||
| 8011 |
4/4✓ Branch 0 taken 130706931 times.
✓ Branch 1 taken 44671500 times.
✓ Branch 2 taken 99274024 times.
✓ Branch 3 taken 31432907 times.
|
175378431 | while (key_part < end_key_part && keypart_map) { |
| 8012 | 99274024 | length += key_part->store_length; | |
| 8013 | 99274024 | keypart_map >>= 1; | |
| 8014 | 99274024 | key_part++; | |
| 8015 | } | ||
| 8016 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 76104407 times.
|
76104407 | if (count) *count = key_part - key_info->key_part; |
| 8017 | |||
| 8018 | 76104407 | return length; | |
| 8019 | } | ||
| 8020 | |||
| 8021 | /** | ||
| 8022 | Returns a list of all known extensions. | ||
| 8023 | |||
| 8024 | No mutexes, worst case race is a minor surplus memory allocation | ||
| 8025 | We have to recreate the extension map if mysqld is restarted (for example | ||
| 8026 | within libmysqld) | ||
| 8027 | |||
| 8028 | @retval | ||
| 8029 | pointer pointer to TYPELIB structure | ||
| 8030 | */ | ||
| 8031 | 55449 | static bool exts_handlerton(THD *, plugin_ref plugin, void *arg) { | |
| 8032 | 55449 | List<const char> *found_exts = static_cast<List<const char> *>(arg); | |
| 8033 | 55449 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 8034 |
4/4✓ Branch 0 taken 55426 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 25347 times.
✓ Branch 3 taken 30079 times.
|
55449 | if (hton->state == SHOW_OPTION_YES && hton->file_extensions) { |
| 8035 |
1/2✓ Branch 0 taken 25347 times.
✗ Branch 1 not taken.
|
25347 | List_iterator_fast<const char> it(*found_exts); |
| 8036 | const char **ext, *old_ext; | ||
| 8037 | |||
| 8038 |
2/2✓ Branch 0 taken 35565 times.
✓ Branch 1 taken 25347 times.
|
60912 | for (ext = hton->file_extensions; *ext; ext++) { |
| 8039 |
2/2✓ Branch 0 taken 106200 times.
✓ Branch 1 taken 35565 times.
|
141765 | while ((old_ext = it++)) { |
| 8040 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 106200 times.
|
106200 | if (!strcmp(old_ext, *ext)) break; |
| 8041 | } | ||
| 8042 |
2/4✓ Branch 0 taken 35565 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 35565 times.
✗ Branch 3 not taken.
|
35565 | if (!old_ext) found_exts->push_back(*ext); |
| 8043 | |||
| 8044 | 35565 | it.rewind(); | |
| 8045 | } | ||
| 8046 | } | ||
| 8047 | 55449 | return false; | |
| 8048 | } | ||
| 8049 | |||
| 8050 | 5109 | TYPELIB *ha_known_exts() { | |
| 8051 |
2/4✓ Branch 0 taken 5109 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5109 times.
✗ Branch 3 not taken.
|
5109 | TYPELIB *known_extensions = (TYPELIB *)(*THR_MALLOC)->Alloc(sizeof(TYPELIB)); |
| 8052 | 5109 | known_extensions->name = "known_exts"; | |
| 8053 | 5109 | known_extensions->type_lengths = nullptr; | |
| 8054 | |||
| 8055 | 5109 | List<const char> found_exts; | |
| 8056 | const char **ext, *old_ext; | ||
| 8057 | |||
| 8058 |
1/2✓ Branch 0 taken 5109 times.
✗ Branch 1 not taken.
|
5109 | plugin_foreach(nullptr, exts_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, |
| 8059 | &found_exts); | ||
| 8060 | |||
| 8061 | 5109 | size_t arr_length = sizeof(char *) * (found_exts.elements + 1); | |
| 8062 |
2/4✓ Branch 0 taken 5109 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5109 times.
✗ Branch 3 not taken.
|
5109 | ext = (const char **)(*THR_MALLOC)->Alloc(arr_length); |
| 8063 | |||
| 8064 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5109 times.
|
5109 | assert(nullptr != ext); |
| 8065 | 5109 | known_extensions->count = found_exts.elements; | |
| 8066 | 5109 | known_extensions->type_names = ext; | |
| 8067 | |||
| 8068 |
1/2✓ Branch 0 taken 5109 times.
✗ Branch 1 not taken.
|
5109 | List_iterator_fast<const char> it(found_exts); |
| 8069 |
2/2✓ Branch 0 taken 35565 times.
✓ Branch 1 taken 5109 times.
|
40674 | while ((old_ext = it++)) *ext++ = old_ext; |
| 8070 | 5109 | *ext = nullptr; | |
| 8071 | 5109 | return known_extensions; | |
| 8072 | } | ||
| 8073 | |||
| 8074 | 12727 | static bool stat_print(THD *thd, const char *type, size_t type_len, | |
| 8075 | const char *file, size_t file_len, const char *status, | ||
| 8076 | size_t status_len) { | ||
| 8077 | 12727 | Protocol *protocol = thd->get_protocol(); | |
| 8078 | 12727 | protocol->start_row(); | |
| 8079 | 12727 | protocol->store_string(type, type_len, system_charset_info); | |
| 8080 | 12727 | protocol->store_string(file, file_len, system_charset_info); | |
| 8081 | 12727 | protocol->store_string(status, status_len, system_charset_info); | |
| 8082 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12727 times.
|
12727 | if (protocol->end_row()) return true; |
| 8083 | 12727 | return false; | |
| 8084 | } | ||
| 8085 | |||
| 8086 | 33 | static bool showstat_handlerton(THD *thd, plugin_ref plugin, void *arg) { | |
| 8087 | 33 | enum ha_stat_type stat = *(enum ha_stat_type *)arg; | |
| 8088 | 33 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 8089 |
4/6✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 33 times.
|
39 | if (hton->state == SHOW_OPTION_YES && hton->show_status && |
| 8090 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | hton->show_status(hton, thd, stat_print, stat)) |
| 8091 | ✗ | return true; | |
| 8092 | 33 | return false; | |
| 8093 | } | ||
| 8094 | |||
| 8095 | 340 | bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) { | |
| 8096 | 340 | mem_root_deque<Item *> field_list(thd->mem_root); | |
| 8097 |
3/6✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 340 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
|
340 | field_list.push_back(new Item_empty_string("Type", 10)); |
| 8098 |
3/6✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 340 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
|
340 | field_list.push_back(new Item_empty_string("Name", FN_REFLEN)); |
| 8099 |
3/6✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 340 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
|
340 | field_list.push_back(new Item_empty_string("Status", 10)); |
| 8100 | |||
| 8101 |
2/4✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 340 times.
|
340 | if (thd->send_result_metadata(field_list, |
| 8102 | Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) | ||
| 8103 | ✗ | return true; | |
| 8104 | |||
| 8105 | bool result; | ||
| 8106 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 337 times.
|
340 | if (db_type == nullptr) { |
| 8107 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | result = plugin_foreach(thd, showstat_handlerton, |
| 8108 | MYSQL_STORAGE_ENGINE_PLUGIN, &stat); | ||
| 8109 | } else { | ||
| 8110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 337 times.
|
337 | if (db_type->state != SHOW_OPTION_YES) { |
| 8111 | ✗ | const LEX_CSTRING *name = &se_plugin_array[db_type->slot]->name; | |
| 8112 | ✗ | result = stat_print(thd, name->str, name->length, "", 0, "DISABLED", 8) | |
| 8113 | ✗ | ? true | |
| 8114 | : false; | ||
| 8115 | } else { | ||
| 8116 |
2/6✓ Branch 0 taken 337 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 337 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
337 | DBUG_EXECUTE_IF("simulate_show_status_failure", |
| 8117 | DBUG_SET("+d,simulate_net_write_failure");); | ||
| 8118 | 674 | result = db_type->show_status && | |
| 8119 |
1/2✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
|
331 | db_type->show_status(db_type, thd, stat_print, stat) |
| 8120 |
3/4✓ Branch 0 taken 331 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 331 times.
|
668 | ? true |
| 8121 | : false; | ||
| 8122 |
2/6✓ Branch 0 taken 337 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 337 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
337 | DBUG_EXECUTE_IF("simulate_show_status_failure", |
| 8123 | DBUG_SET("-d,simulate_net_write_failure");); | ||
| 8124 | } | ||
| 8125 | } | ||
| 8126 | |||
| 8127 |
2/4✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 340 times.
✗ Branch 3 not taken.
|
340 | if (!result) my_eof(thd); |
| 8128 | 340 | return result; | |
| 8129 | 340 | } | |
| 8130 | |||
| 8131 | /* | ||
| 8132 | Function to check if the conditions for row-based binlogging is | ||
| 8133 | correct for the table. | ||
| 8134 | |||
| 8135 | A row in the given table should be replicated if: | ||
| 8136 | - Row-based replication is enabled in the current thread | ||
| 8137 | - The binlog is enabled | ||
| 8138 | - It is not a temporary table | ||
| 8139 | - The binary log is open | ||
| 8140 | - The database the table resides in shall be binlogged (binlog_*_db rules) | ||
| 8141 | - table is not mysql.event | ||
| 8142 | */ | ||
| 8143 | |||
| 8144 | 174314708 | static bool check_table_binlog_row_based(THD *thd, TABLE *table) { | |
| 8145 |
2/2✓ Branch 0 taken 802222 times.
✓ Branch 1 taken 173512486 times.
|
174314708 | if (table->s->cached_row_logging_check == -1) { |
| 8146 | 1108753 | int const check(table->s->tmp_table == NO_TMP_TABLE && | |
| 8147 |
4/4✓ Branch 0 taken 306531 times.
✓ Branch 1 taken 495691 times.
✓ Branch 2 taken 284940 times.
✓ Branch 3 taken 21591 times.
|
1087162 | !table->no_replicate && |
| 8148 |
2/2✓ Branch 0 taken 284801 times.
✓ Branch 1 taken 139 times.
|
284940 | binlog_filter->db_ok(table->s->db.str)); |
| 8149 | 802222 | table->s->cached_row_logging_check = check; | |
| 8150 | } | ||
| 8151 | |||
| 8152 |
3/4✓ Branch 0 taken 84238628 times.
✓ Branch 1 taken 90076080 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84238628 times.
|
174314708 | assert(table->s->cached_row_logging_check == 0 || |
| 8153 | table->s->cached_row_logging_check == 1); | ||
| 8154 | |||
| 8155 | #ifdef WITH_WSREP | ||
| 8156 | /* | ||
| 8157 | In addition to above conditions, PXC allows replication if: | ||
| 8158 | 1. Binlogging was not disabled internally by the server with the | ||
| 8159 | explicit intention to not replicate (OPTION_BIN_LOG_INTERNAL_OFF flag) | ||
| 8160 | 2a. We are in binlog emulation mode and current thread is not applier thread | ||
| 8161 | 2b. PXC replication for current is enabled (wsrep_on == true) | ||
| 8162 | */ | ||
| 8163 | 174314708 | return (thd->is_current_stmt_binlog_format_row() && | |
| 8164 |
2/2✓ Branch 0 taken 63767327 times.
✓ Branch 1 taken 83365846 times.
|
147133173 | table->s->cached_row_logging_check && |
| 8165 |
6/6✓ Branch 0 taken 147133173 times.
✓ Branch 1 taken 27181902 times.
✓ Branch 2 taken 59246271 times.
✓ Branch 3 taken 4521056 times.
✓ Branch 4 taken 59246258 times.
✓ Branch 5 taken 13 times.
|
380694302 | !(thd->variables.option_bits & OPTION_BIN_LOG_INTERNAL_OFF) && |
| 8166 |
11/12✓ Branch 0 taken 13583750 times.
✓ Branch 1 taken 45662508 times.
✓ Branch 2 taken 13045304 times.
✓ Branch 3 taken 538446 times.
✓ Branch 4 taken 13045298 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 190223 times.
✓ Branch 7 taken 12855075 times.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 190220 times.
✓ Branch 10 taken 59056051 times.
✗ Branch 11 not taken.
|
59246271 | (((WSREP_EMULATE_BINLOG(thd) && (!wsrep_thd_is_applying(thd))) || |
| 8167 |
10/10✓ Branch 0 taken 13393527 times.
✓ Branch 1 taken 45662524 times.
✓ Branch 2 taken 12855081 times.
✓ Branch 3 taken 538446 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 12855075 times.
✓ Branch 6 taken 46139200 times.
✓ Branch 7 taken 61776 times.
✓ Branch 8 taken 58252434 times.
✓ Branch 9 taken 741624 times.
|
118050109 | (((WSREP(thd) || thd->variables.option_bits & OPTION_BIN_LOG)) && |
| 8168 | 233309133 | mysql_bin_log.is_open())))); | |
| 8169 | #else | ||
| 8170 | return (thd->is_current_stmt_binlog_format_row() && | ||
| 8171 | table->s->cached_row_logging_check && | ||
| 8172 | (thd->variables.option_bits & OPTION_BIN_LOG) && | ||
| 8173 | mysql_bin_log.is_open()); | ||
| 8174 | #endif | ||
| 8175 | } | ||
| 8176 | |||
| 8177 | /** @brief | ||
| 8178 | Write table maps for all (manually or automatically) locked tables | ||
| 8179 | to the binary log. | ||
| 8180 | |||
| 8181 | SYNOPSIS | ||
| 8182 | write_locked_table_maps() | ||
| 8183 | thd Pointer to THD structure | ||
| 8184 | |||
| 8185 | DESCRIPTION | ||
| 8186 | This function will generate and write table maps for all tables | ||
| 8187 | that are locked by the thread 'thd'. | ||
| 8188 | |||
| 8189 | RETURN VALUE | ||
| 8190 | 0 All OK | ||
| 8191 | 1 Failed to write all table maps | ||
| 8192 | |||
| 8193 | SEE ALSO | ||
| 8194 | THD::lock | ||
| 8195 | */ | ||
| 8196 | |||
| 8197 | 47727136 | static int write_locked_table_maps(THD *thd) { | |
| 8198 |
1/2✓ Branch 0 taken 47727182 times.
✗ Branch 1 not taken.
|
47727136 | DBUG_TRACE; |
| 8199 |
5/8✓ Branch 0 taken 47727160 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47727156 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
✓ Branch 5 taken 47727110 times.
✓ Branch 6 taken 46 times.
✗ Branch 7 not taken.
|
47727182 | DBUG_PRINT("enter", ("thd: %p thd->lock: %p " |
| 8200 | "thd->extra_lock: %p", | ||
| 8201 | thd, thd->lock, thd->extra_lock)); | ||
| 8202 | |||
| 8203 |
5/8✓ Branch 0 taken 47727080 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47727124 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
✓ Branch 5 taken 47727078 times.
✓ Branch 6 taken 46 times.
✗ Branch 7 not taken.
|
47727156 | DBUG_PRINT("debug", |
| 8204 | ("get_binlog_table_maps(): %d", thd->get_binlog_table_maps())); | ||
| 8205 | |||
| 8206 |
2/2✓ Branch 0 taken 4233325 times.
✓ Branch 1 taken 43493779 times.
|
47727124 | if (thd->get_binlog_table_maps() == 0) { |
| 8207 |
2/2✓ Branch 0 taken 8466138 times.
✓ Branch 1 taken 4233072 times.
|
12699473 | for (MYSQL_LOCK *lock : {thd->extra_lock, thd->lock}) { |
| 8208 |
2/2✓ Branch 0 taken 4229211 times.
✓ Branch 1 taken 4236927 times.
|
8466138 | if (lock == nullptr) continue; |
| 8209 | |||
| 8210 | 4236927 | bool need_binlog_rows_query = thd->variables.binlog_rows_query_log_events; | |
| 8211 | 4236927 | TABLE **const end_ptr = lock->table + lock->table_count; | |
| 8212 |
2/2✓ Branch 0 taken 4404574 times.
✓ Branch 1 taken 4236937 times.
|
8641511 | for (TABLE **table_ptr = lock->table; table_ptr != end_ptr; ++table_ptr) { |
| 8213 | 4404574 | TABLE *const table = *table_ptr; | |
| 8214 |
5/8✓ Branch 0 taken 4404590 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4404580 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 31 times.
✓ Branch 5 taken 4404549 times.
✓ Branch 6 taken 37 times.
✗ Branch 7 not taken.
|
4404574 | DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str)); |
| 8215 |
4/4✓ Branch 0 taken 4247148 times.
✓ Branch 1 taken 157438 times.
✓ Branch 2 taken 4247147 times.
✓ Branch 3 taken 157459 times.
|
8651754 | if (table->current_lock == F_WRLCK && |
| 8216 |
3/4✓ Branch 0 taken 4247168 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4247158 times.
✓ Branch 3 taken 10 times.
|
4247148 | check_table_binlog_row_based(thd, table)) { |
| 8217 | /* | ||
| 8218 | We need to have a transactional behavior for SQLCOM_CREATE_TABLE | ||
| 8219 | (e.g. CREATE TABLE... SELECT * FROM TABLE) in order to keep a | ||
| 8220 | compatible behavior with the STMT based replication even when | ||
| 8221 | the table is not transactional. In other words, if the operation | ||
| 8222 | fails while executing the insert phase nothing is written to the | ||
| 8223 | binlog. | ||
| 8224 | |||
| 8225 | Note that at this point, we check the type of a set of tables to | ||
| 8226 | create the table map events. In the function binlog_log_row(), | ||
| 8227 | which calls the current function, we check the type of the table | ||
| 8228 | of the current row. | ||
| 8229 | */ | ||
| 8230 |
4/4✓ Branch 0 taken 4239749 times.
✓ Branch 1 taken 7398 times.
✓ Branch 2 taken 3909301 times.
✓ Branch 3 taken 330431 times.
|
8486879 | bool const has_trans = thd->lex->sql_command == SQLCOM_CREATE_TABLE || |
| 8231 | 4239749 | table->file->has_transactions(); | |
| 8232 |
1/2✓ Branch 0 taken 4247153 times.
✗ Branch 1 not taken.
|
4247130 | int const error = thd->binlog_write_table_map(table, has_trans, |
| 8233 | need_binlog_rows_query); | ||
| 8234 | /* Binlog Rows_query log event once for one statement which updates | ||
| 8235 | two or more tables.*/ | ||
| 8236 |
2/2✓ Branch 0 taken 77 times.
✓ Branch 1 taken 4247076 times.
|
4247153 | if (need_binlog_rows_query) need_binlog_rows_query = false; |
| 8237 | /* | ||
| 8238 | If an error occurs, it is the responsibility of the caller to | ||
| 8239 | roll back the transaction. | ||
| 8240 | */ | ||
| 8241 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4247125 times.
|
4247153 | if (unlikely(error)) return 1; |
| 8242 | } | ||
| 8243 | } | ||
| 8244 | } | ||
| 8245 | } | ||
| 8246 | 47726851 | return 0; | |
| 8247 | 47726851 | } | |
| 8248 | |||
| 8249 | /** | ||
| 8250 | The purpose of an instance of this class is to : | ||
| 8251 | |||
| 8252 | 1) Given a TABLE instance, backup the given TABLE::read_set, TABLE::write_set | ||
| 8253 | and restore those members upon this instance disposal. | ||
| 8254 | |||
| 8255 | 2) Store a reference to a dynamically allocated buffer and dispose of it upon | ||
| 8256 | this instance disposal. | ||
| 8257 | */ | ||
| 8258 | |||
| 8259 | class Binlog_log_row_cleanup { | ||
| 8260 | public: | ||
| 8261 | /** | ||
| 8262 | This constructor aims to create temporary copies of readset and writeset. | ||
| 8263 | |||
| 8264 | @param table A pointer to TABLE object | ||
| 8265 | @param temp_read_bitmap Temporary BITMAP to store read_set. | ||
| 8266 | @param temp_write_bitmap Temporary BITMAP to store write_set. | ||
| 8267 | */ | ||
| 8268 | 47727035 | Binlog_log_row_cleanup(TABLE &table, MY_BITMAP &temp_read_bitmap, | |
| 8269 | |||
| 8270 | MY_BITMAP &temp_write_bitmap) | ||
| 8271 | |||
| 8272 | 47727035 | : m_cleanup_table(table), | |
| 8273 | 47727035 | m_cleanup_read_bitmap(temp_read_bitmap), | |
| 8274 | 47727035 | m_cleanup_write_bitmap(temp_write_bitmap) { | |
| 8275 | 47727035 | bitmap_copy(&this->m_cleanup_read_bitmap, this->m_cleanup_table.read_set); | |
| 8276 | 47727196 | bitmap_copy(&this->m_cleanup_write_bitmap, this->m_cleanup_table.write_set); | |
| 8277 | 47727215 | } | |
| 8278 | |||
| 8279 | /** | ||
| 8280 | This destructor aims to restore the original readset and writeset and | ||
| 8281 | delete the temporary copies. | ||
| 8282 | */ | ||
| 8283 | 95454128 | virtual ~Binlog_log_row_cleanup() { | |
| 8284 | 95454128 | bitmap_copy(this->m_cleanup_table.read_set, &this->m_cleanup_read_bitmap); | |
| 8285 | 95454400 | bitmap_copy(this->m_cleanup_table.write_set, &this->m_cleanup_write_bitmap); | |
| 8286 | 95454426 | bitmap_free(&this->m_cleanup_read_bitmap); | |
| 8287 | 95454442 | bitmap_free(&this->m_cleanup_write_bitmap); | |
| 8288 | } | ||
| 8289 | |||
| 8290 | private: | ||
| 8291 | TABLE &m_cleanup_table; // Creating a TABLE to get access to its members. | ||
| 8292 | MY_BITMAP &m_cleanup_read_bitmap; // Temporary bitmap to store read_set. | ||
| 8293 | MY_BITMAP &m_cleanup_write_bitmap; // Temporary bitmap to store write_set. | ||
| 8294 | }; | ||
| 8295 | |||
| 8296 | 163152897 | int binlog_log_row(TABLE *table, const uchar *before_record, | |
| 8297 | const uchar *after_record, Log_func *log_func) { | ||
| 8298 | 163152897 | bool error = false; | |
| 8299 | 163152897 | THD *const thd = table->in_use; | |
| 8300 | |||
| 8301 |
2/2✓ Branch 0 taken 47727039 times.
✓ Branch 1 taken 115425900 times.
|
163152897 | if (check_table_binlog_row_based(thd, table)) { |
| 8302 |
1/2✓ Branch 0 taken 47727097 times.
✗ Branch 1 not taken.
|
47727039 | if (thd->variables.transaction_write_set_extraction != HASH_ALGORITHM_OFF) { |
| 8303 | try { | ||
| 8304 | 47727097 | MY_BITMAP save_read_set; | |
| 8305 | 47727097 | MY_BITMAP save_write_set; | |
| 8306 |
3/6✓ Branch 0 taken 47727100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47727129 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 47727211 times.
|
95454337 | if (bitmap_init(&save_read_set, nullptr, table->s->fields) || |
| 8307 |
2/4✓ Branch 0 taken 47727240 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47727241 times.
|
47727129 | bitmap_init(&save_write_set, nullptr, table->s->fields)) { |
| 8308 | ✗ | my_error(ER_OUT_OF_RESOURCES, MYF(0)); | |
| 8309 | ✗ | return HA_ERR_RBR_LOGGING_FAILED; | |
| 8310 | } | ||
| 8311 | |||
| 8312 | Binlog_log_row_cleanup cleanup_sentry(*table, save_read_set, | ||
| 8313 |
1/2✓ Branch 0 taken 47727192 times.
✗ Branch 1 not taken.
|
47727211 | save_write_set); |
| 8314 | |||
| 8315 |
2/2✓ Branch 0 taken 15407 times.
✓ Branch 1 taken 47711785 times.
|
47727192 | if (thd->variables.binlog_row_image == 0) { |
| 8316 |
2/2✓ Branch 0 taken 12596 times.
✓ Branch 1 taken 15407 times.
|
28003 | for (uint key_number = 0; key_number < table->s->keys; ++key_number) { |
| 8317 |
2/2✓ Branch 0 taken 9438 times.
✓ Branch 1 taken 3158 times.
|
12596 | if (((table->key_info[key_number].flags & (HA_NOSAME)) == |
| 8318 | HA_NOSAME)) { | ||
| 8319 |
1/2✓ Branch 0 taken 9438 times.
✗ Branch 1 not taken.
|
9438 | table->mark_columns_used_by_index_no_reset(key_number, |
| 8320 | table->read_set); | ||
| 8321 |
1/2✓ Branch 0 taken 9438 times.
✗ Branch 1 not taken.
|
9438 | table->mark_columns_used_by_index_no_reset(key_number, |
| 8322 | table->write_set); | ||
| 8323 | } | ||
| 8324 | } | ||
| 8325 | } | ||
| 8326 | 47727192 | std::array<const uchar *, 2> records{after_record, before_record}; | |
| 8327 |
2/2✓ Branch 0 taken 95454003 times.
✓ Branch 1 taken 47727188 times.
|
143181485 | for (auto rec : records) { |
| 8328 |
2/2✓ Branch 0 taken 51542387 times.
✓ Branch 1 taken 43911616 times.
|
95454003 | if (rec != nullptr) { |
| 8329 |
3/4✓ Branch 0 taken 3815652 times.
✓ Branch 1 taken 47726735 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3815652 times.
|
51542387 | assert(rec == table->record[0] || rec == table->record[1]); |
| 8330 |
1/2✓ Branch 0 taken 51542677 times.
✗ Branch 1 not taken.
|
51542387 | bool res = add_pke(table, thd, rec); |
| 8331 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51542677 times.
|
51542677 | if (res) return HA_ERR_RBR_LOGGING_FAILED; |
| 8332 | } | ||
| 8333 | } | ||
| 8334 |
1/4✓ Branch 0 taken 47727241 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
47727188 | } catch (const std::bad_alloc &) { |
| 8335 | ✗ | my_error(ER_OUT_OF_RESOURCES, MYF(0)); | |
| 8336 | ✗ | return HA_ERR_RBR_LOGGING_FAILED; | |
| 8337 | } | ||
| 8338 | } | ||
| 8339 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 47727215 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
47727183 | if (table->in_use->is_error()) return error ? HA_ERR_RBR_LOGGING_FAILED : 0; |
| 8340 | |||
| 8341 | 47727215 | DBUG_DUMP("read_set 10", (uchar *)table->read_set->bitmap, | |
| 8342 | (table->s->fields + 7) / 8); | ||
| 8343 | |||
| 8344 | /* | ||
| 8345 | If there are no table maps written to the binary log, this is | ||
| 8346 | the first row handled in this statement. In that case, we need | ||
| 8347 | to write table maps for all locked tables to the binary log. | ||
| 8348 | */ | ||
| 8349 |
2/2✓ Branch 0 taken 47727219 times.
✓ Branch 1 taken 92 times.
|
47727183 | if (likely(!(error = write_locked_table_maps(thd)))) { |
| 8350 | /* | ||
| 8351 | We need to have a transactional behavior for SQLCOM_CREATE_TABLE | ||
| 8352 | (i.e. CREATE TABLE... SELECT * FROM TABLE) in order to keep a | ||
| 8353 | compatible behavior with the STMT based replication even when | ||
| 8354 | the table is not transactional. In other words, if the operation | ||
| 8355 | fails while executing the insert phase nothing is written to the | ||
| 8356 | binlog. | ||
| 8357 | */ | ||
| 8358 |
4/4✓ Branch 0 taken 45855902 times.
✓ Branch 1 taken 1871317 times.
✓ Branch 2 taken 42072310 times.
✓ Branch 3 taken 3783443 times.
|
93582972 | bool const has_trans = thd->lex->sql_command == SQLCOM_CREATE_TABLE || |
| 8359 | 45855902 | table->file->has_transactions(); | |
| 8360 | 47727070 | error = (*log_func)(thd, table, has_trans, before_record, after_record); | |
| 8361 | } | ||
| 8362 | } | ||
| 8363 | |||
| 8364 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 163152679 times.
|
163152687 | return error ? HA_ERR_RBR_LOGGING_FAILED : 0; |
| 8365 | } | ||
| 8366 | |||
| 8367 | 233049417 | int handler::ha_external_lock(THD *thd, int lock_type) { | |
| 8368 | int error; | ||
| 8369 |
1/2✓ Branch 0 taken 233052921 times.
✗ Branch 1 not taken.
|
233049417 | DBUG_TRACE; |
| 8370 | /* | ||
| 8371 | Whether this is lock or unlock, this should be true, and is to verify that | ||
| 8372 | if get_auto_increment() was called (thus may have reserved intervals or | ||
| 8373 | taken a table lock), ha_release_auto_increment() was too. | ||
| 8374 | */ | ||
| 8375 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 233052921 times.
|
233052921 | assert(next_insert_id == 0); |
| 8376 | /* Consecutive calls for lock without unlocking in between is not allowed */ | ||
| 8377 |
6/8✓ Branch 0 taken 232550482 times.
✓ Branch 1 taken 502439 times.
✓ Branch 2 taken 116276585 times.
✓ Branch 3 taken 116273897 times.
✓ Branch 4 taken 116276624 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 116273858 times.
|
233052921 | assert(table_share->tmp_table != NO_TMP_TABLE || |
| 8378 | ((lock_type != F_UNLCK && m_lock_type == F_UNLCK) || | ||
| 8379 | lock_type == F_UNLCK)); | ||
| 8380 | /* SQL HANDLER call locks/unlock while scanning (RND/INDEX). */ | ||
| 8381 |
3/4✓ Branch 0 taken 708 times.
✓ Branch 1 taken 233052213 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 708 times.
|
233052921 | assert(inited == NONE || table->open_by_handler); |
| 8382 | |||
| 8383 |
1/2✓ Branch 0 taken 233053103 times.
✗ Branch 1 not taken.
|
233052921 | ha_statistic_increment(&System_status_var::ha_external_lock_count); |
| 8384 | |||
| 8385 |
8/12✓ Branch 0 taken 31141958 times.
✓ Branch 1 taken 201911145 times.
✓ Branch 2 taken 31140736 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 31141315 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15560142 times.
✓ Branch 7 taken 15581173 times.
✓ Branch 8 taken 15560061 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 201911055 times.
✗ Branch 11 not taken.
|
233053103 | MYSQL_TABLE_LOCK_WAIT(PSI_TABLE_EXTERNAL_LOCK, lock_type, |
| 8386 | { error = external_lock(thd, lock_type); }) | ||
| 8387 | |||
| 8388 | /* | ||
| 8389 | We cache the table flags if the locking succeeded. Otherwise, we | ||
| 8390 | keep them as they were when they were fetched in ha_open(). | ||
| 8391 | */ | ||
| 8392 | |||
| 8393 |
2/2✓ Branch 0 taken 233051555 times.
✓ Branch 1 taken 734 times.
|
233052289 | if (error == 0) { |
| 8394 | /* | ||
| 8395 | The lock type is needed by MRR when creating a clone of this handler | ||
| 8396 | object. | ||
| 8397 | */ | ||
| 8398 | 233051555 | m_lock_type = lock_type; | |
| 8399 |
1/2✓ Branch 0 taken 233050689 times.
✗ Branch 1 not taken.
|
233051555 | cached_table_flags = table_flags(); |
| 8400 | } | ||
| 8401 | |||
| 8402 | 233051988 | return error; | |
| 8403 | 233051423 | } | |
| 8404 | |||
| 8405 | /** @brief | ||
| 8406 | Check handler usage and reset state of file to after 'open' | ||
| 8407 | |||
| 8408 | @note can be called regardless of it is locked or not. | ||
| 8409 | */ | ||
| 8410 | 108793181 | int handler::ha_reset() { | |
| 8411 |
1/2✓ Branch 0 taken 108794444 times.
✗ Branch 1 not taken.
|
108793181 | DBUG_TRACE; |
| 8412 | /* Check that we have called all proper deallocation functions */ | ||
| 8413 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 108794444 times.
|
108794444 | assert((uchar *)table->def_read_set.bitmap + table->s->column_bitmap_size == |
| 8414 | (uchar *)table->def_write_set.bitmap); | ||
| 8415 |
2/4✓ Branch 0 taken 108793986 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108793986 times.
|
108794444 | assert(bitmap_is_set_all(&table->s->all_set)); |
| 8416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 108793986 times.
|
108793986 | assert(table->key_read == 0); |
| 8417 | /* ensure that ha_index_end / ha_rnd_end has been called */ | ||
| 8418 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 108793986 times.
|
108793986 | assert(inited == NONE); |
| 8419 | /* Free cache used by filesort */ | ||
| 8420 |
1/2✓ Branch 0 taken 108793344 times.
✗ Branch 1 not taken.
|
108793986 | free_io_cache(table); |
| 8421 | /* reset the bitmaps to point to defaults */ | ||
| 8422 | 108793344 | table->default_column_bitmaps(); | |
| 8423 | /* Reset the handler flags used for dupilcate record handling */ | ||
| 8424 |
1/2✓ Branch 0 taken 108793826 times.
✗ Branch 1 not taken.
|
108793659 | table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); |
| 8425 |
1/2✓ Branch 0 taken 108794302 times.
✗ Branch 1 not taken.
|
108793826 | table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); |
| 8426 | /* Reset information about pushed engine conditions */ | ||
| 8427 | 108794302 | pushed_cond = nullptr; | |
| 8428 | /* Reset information about pushed index conditions */ | ||
| 8429 |
1/2✓ Branch 0 taken 108791870 times.
✗ Branch 1 not taken.
|
108794302 | cancel_pushed_idx_cond(); |
| 8430 | // Forget the record buffer. | ||
| 8431 | 108791870 | m_record_buffer = nullptr; | |
| 8432 | 108791870 | m_unique = nullptr; | |
| 8433 | |||
| 8434 |
1/2✓ Branch 0 taken 108794016 times.
✗ Branch 1 not taken.
|
108791870 | const int retval = reset(); |
| 8435 | 108794592 | return retval; | |
| 8436 | 108794016 | } | |
| 8437 | |||
| 8438 | #ifdef WITH_WSREP | ||
| 8439 | 6468525 | static int wsrep_after_row(THD *thd) { | |
| 8440 |
1/2✓ Branch 0 taken 6468530 times.
✗ Branch 1 not taken.
|
6468525 | DBUG_TRACE; |
| 8441 | |||
| 8442 | /* enforce wsrep_max_ws_rows */ | ||
| 8443 | 6468530 | thd->wsrep_affected_rows++; | |
| 8444 |
6/8✓ Branch 0 taken 60366 times.
✓ Branch 1 taken 6408164 times.
✓ Branch 2 taken 60366 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 60366 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 6468512 times.
|
6528896 | if (wsrep_max_ws_rows && wsrep_thd_is_local(thd) && |
| 8445 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 60348 times.
|
60366 | thd->wsrep_affected_rows > wsrep_max_ws_rows) { |
| 8446 |
4/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 18 times.
|
18 | trans_rollback_stmt(thd) || trans_rollback(thd); |
| 8447 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0)); |
| 8448 | 18 | return ER_ERROR_DURING_COMMIT; | |
| 8449 |
3/4✓ Branch 0 taken 6468512 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 6468508 times.
|
6468512 | } else if (wsrep_after_row(thd, false)) { |
| 8450 | 4 | return ER_LOCK_DEADLOCK; | |
| 8451 | } | ||
| 8452 | 6468508 | return 0; | |
| 8453 | 6468530 | } | |
| 8454 | #endif /* WITH_WSREP */ | ||
| 8455 | |||
| 8456 | 145202077 | int handler::ha_write_row(uchar *buf) { | |
| 8457 | int error; | ||
| 8458 | 145202077 | Log_func *log_func = Write_rows_log_event::binlog_row_logging_function; | |
| 8459 |
3/4✓ Branch 0 taken 58792471 times.
✓ Branch 1 taken 86409606 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58792471 times.
|
145202077 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK); |
| 8460 | |||
| 8461 |
1/2✓ Branch 0 taken 124232248 times.
✗ Branch 1 not taken.
|
145202077 | DBUG_TRACE; |
| 8462 |
4/6✓ Branch 0 taken 123284270 times.
✓ Branch 1 taken 947686 times.
✓ Branch 2 taken 123284420 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 141429202 times.
✗ Branch 5 not taken.
|
124232248 | DEBUG_SYNC(ha_thd(), "start_ha_write_row"); |
| 8463 |
3/4✓ Branch 0 taken 145203908 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 145203907 times.
|
142376888 | DBUG_EXECUTE_IF("inject_error_ha_write_row", return HA_ERR_INTERNAL_ERROR;); |
| 8464 |
2/4✓ Branch 0 taken 145203881 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 145203881 times.
|
145203907 | DBUG_EXECUTE_IF("simulate_storage_engine_out_of_memory", |
| 8465 | return HA_ERR_SE_OUT_OF_MEMORY;); | ||
| 8466 |
1/2✓ Branch 0 taken 145202979 times.
✗ Branch 1 not taken.
|
145203881 | mark_trx_read_write(); |
| 8467 | |||
| 8468 |
2/8✓ Branch 0 taken 145203493 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 145203493 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
145202979 | DBUG_EXECUTE_IF( |
| 8469 | "handler_crashed_table_on_usage", | ||
| 8470 | my_error(HA_ERR_CRASHED, MYF(ME_ERRORLOG), table_share->table_name.str); | ||
| 8471 | set_my_errno(HA_ERR_CRASHED); return HA_ERR_CRASHED;); | ||
| 8472 | |||
| 8473 |
9/27✓ Branch 0 taken 43765618 times.
✓ Branch 1 taken 101437875 times.
✓ Branch 2 taken 43766058 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 43765311 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 43766061 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 42651733 times.
✓ Branch 10 taken 1114328 times.
✓ Branch 11 taken 42651927 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 101437778 times.
✗ Branch 26 not taken.
|
145203493 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_WRITE_ROW, MAX_KEY, error, |
| 8474 | { error = write_row(buf); }) | ||
| 8475 | |||
| 8476 |
2/2✓ Branch 0 taken 4784041 times.
✓ Branch 1 taken 140420006 times.
|
145204033 | if (unlikely(error)) return error; |
| 8477 | |||
| 8478 |
3/4✓ Branch 0 taken 140419074 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 140419572 times.
|
140420006 | if (unlikely((error = binlog_log_row(table, nullptr, buf, log_func)))) |
| 8479 | 4 | return error; /* purecov: inspected */ | |
| 8480 | |||
| 8481 | #ifdef WITH_WSREP | ||
| 8482 | /* With MySQL-8.0 DDL action would result in altering of InnoDB | ||
| 8483 | system table. Logic below should avoid considering alter of InnoDB | ||
| 8484 | system table to increase affected rows. To cover the same, logic | ||
| 8485 | is now expanded to include binlog check. InnoDB flow suppresses | ||
| 8486 | binlogging of the changes that it does to DDL table as part of DDL | ||
| 8487 | execution. */ | ||
| 8488 |
13/16✓ Branch 0 taken 140420013 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 140420051 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17716619 times.
✓ Branch 5 taken 122703432 times.
✓ Branch 6 taken 9942387 times.
✓ Branch 7 taken 7774232 times.
✓ Branch 8 taken 9942388 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9370640 times.
✓ Branch 11 taken 571748 times.
✓ Branch 12 taken 5689619 times.
✓ Branch 13 taken 3681021 times.
✓ Branch 14 taken 5430004 times.
✓ Branch 15 taken 134990012 times.
|
146109193 | if (WSREP(ha_thd()) && table->s->tmp_table == NO_TMP_TABLE && |
| 8489 |
4/6✓ Branch 0 taken 5689621 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5689621 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5430005 times.
✓ Branch 5 taken 259616 times.
|
5689619 | check_table_binlog_row_based(ha_thd(), table)) { |
| 8490 |
4/6✓ Branch 0 taken 5430003 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5430005 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 5429990 times.
|
5430004 | if ((error = wsrep_after_row(ha_thd()))) { |
| 8491 | 15 | return error; | |
| 8492 | } | ||
| 8493 | } | ||
| 8494 | #endif /* WITH_WSREP */ | ||
| 8495 | |||
| 8496 | 140420002 | rows_changed++; | |
| 8497 | |||
| 8498 |
3/4✓ Branch 0 taken 136677715 times.
✓ Branch 1 taken 3742287 times.
✓ Branch 2 taken 136677834 times.
✗ Branch 3 not taken.
|
140420002 | DEBUG_SYNC_C("ha_write_row_end"); |
| 8499 | 140420121 | return 0; | |
| 8500 | 145204182 | } | |
| 8501 | |||
| 8502 | 20261142 | int handler::ha_update_row(const uchar *old_data, uchar *new_data) { | |
| 8503 | int error; | ||
| 8504 |
3/4✓ Branch 0 taken 13765047 times.
✓ Branch 1 taken 6496095 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13765047 times.
|
20261142 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK); |
| 8505 | 20261142 | Log_func *log_func = Update_rows_log_event::binlog_row_logging_function; | |
| 8506 | |||
| 8507 | /* | ||
| 8508 | Some storage engines require that the new record is in record[0] | ||
| 8509 | (and the old record is in record[1]). | ||
| 8510 | */ | ||
| 8511 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20261142 times.
|
20261142 | assert(new_data == table->record[0]); |
| 8512 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20261142 times.
|
20261142 | assert(old_data == table->record[1]); |
| 8513 | |||
| 8514 | 20261142 | mark_trx_read_write(); | |
| 8515 | |||
| 8516 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20261150 times.
|
20261155 | DBUG_EXECUTE_IF( |
| 8517 | "handler_crashed_table_on_usage", | ||
| 8518 | my_error(HA_ERR_CRASHED, MYF(ME_ERRORLOG), table_share->table_name.str); | ||
| 8519 | set_my_errno(HA_ERR_CRASHED); return (HA_ERR_CRASHED);); | ||
| 8520 | |||
| 8521 |
11/19✓ Branch 0 taken 4264617 times.
✓ Branch 1 taken 15996533 times.
✓ Branch 2 taken 4263819 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 798 times.
✓ Branch 5 taken 4263819 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4263807 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4262903 times.
✓ Branch 10 taken 904 times.
✓ Branch 11 taken 4262903 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 798 times.
✓ Branch 17 taken 798 times.
✗ Branch 18 not taken.
|
20261150 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_UPDATE_ROW, active_index, error, |
| 8522 | { error = update_row(old_data, new_data); }) | ||
| 8523 | |||
| 8524 |
2/2✓ Branch 0 taken 7292374 times.
✓ Branch 1 taken 12968768 times.
|
20261133 | if (unlikely(error)) return error; |
| 8525 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12968765 times.
|
12968768 | if (unlikely((error = binlog_log_row(table, old_data, new_data, log_func)))) |
| 8526 | 2 | return error; | |
| 8527 | |||
| 8528 | #ifdef WITH_WSREP | ||
| 8529 | /* With MySQL-8.0 DDL action would result in altering of InnoDB | ||
| 8530 | system table. Logic below should avoid considering alter of InnoDB | ||
| 8531 | system table to increase affected rows. To cover the same, logic | ||
| 8532 | is now expanded to include binlog check. InnoDB flow suppresses | ||
| 8533 | binlogging of the changes that it does to DDL table as part of DDL | ||
| 8534 | execution. */ | ||
| 8535 |
11/12✓ Branch 0 taken 12968772 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1415099 times.
✓ Branch 3 taken 11553673 times.
✓ Branch 4 taken 1105976 times.
✓ Branch 5 taken 309123 times.
✓ Branch 6 taken 1100705 times.
✓ Branch 7 taken 5271 times.
✓ Branch 8 taken 1089471 times.
✓ Branch 9 taken 11234 times.
✓ Branch 10 taken 1014157 times.
✓ Branch 11 taken 11954607 times.
|
14058229 | if (WSREP(ha_thd()) && table->s->tmp_table == NO_TMP_TABLE && |
| 8536 |
2/2✓ Branch 0 taken 1014157 times.
✓ Branch 1 taken 75307 times.
|
1089471 | check_table_binlog_row_based(ha_thd(), table)) { |
| 8537 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1014160 times.
|
1014157 | if ((error = wsrep_after_row(ha_thd()))) { |
| 8538 | 3 | return error; | |
| 8539 | } | ||
| 8540 | } | ||
| 8541 | #endif /* WITH_WSREP */ | ||
| 8542 | |||
| 8543 | 12968767 | rows_changed++; | |
| 8544 | 12968767 | return 0; | |
| 8545 | } | ||
| 8546 | |||
| 8547 | 9764495 | int handler::ha_delete_row(const uchar *buf) { | |
| 8548 | int error; | ||
| 8549 |
3/4✓ Branch 0 taken 9758854 times.
✓ Branch 1 taken 5641 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9758854 times.
|
9764495 | assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK); |
| 8550 | 9764495 | Log_func *log_func = Delete_rows_log_event::binlog_row_logging_function; | |
| 8551 | /* | ||
| 8552 | Normally table->record[0] is used, but sometimes table->record[1] is used. | ||
| 8553 | */ | ||
| 8554 |
3/4✓ Branch 0 taken 7327708 times.
✓ Branch 1 taken 2436787 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7327708 times.
|
9764495 | assert(buf == table->record[0] || buf == table->record[1]); |
| 8555 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9764496 times.
|
9764495 | DBUG_EXECUTE_IF("inject_error_ha_delete_row", return HA_ERR_INTERNAL_ERROR;); |
| 8556 | |||
| 8557 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9764496 times.
|
9764496 | DBUG_EXECUTE_IF( |
| 8558 | "handler_crashed_table_on_usage", | ||
| 8559 | my_error(HA_ERR_CRASHED, MYF(ME_ERRORLOG), table_share->table_name.str); | ||
| 8560 | set_my_errno(HA_ERR_CRASHED); return (HA_ERR_CRASHED);); | ||
| 8561 | |||
| 8562 | 9764496 | mark_trx_read_write(); | |
| 8563 | |||
| 8564 |
13/19✓ Branch 0 taken 2148024 times.
✓ Branch 1 taken 7616473 times.
✓ Branch 2 taken 2147851 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 172 times.
✓ Branch 5 taken 2147851 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2147851 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2147824 times.
✓ Branch 10 taken 27 times.
✓ Branch 11 taken 2147824 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 172 times.
✓ Branch 17 taken 172 times.
✗ Branch 18 not taken.
|
9764497 | MYSQL_TABLE_IO_WAIT(PSI_TABLE_DELETE_ROW, active_index, error, |
| 8565 | { error = delete_row(buf); }) | ||
| 8566 | |||
| 8567 |
2/2✓ Branch 0 taken 78 times.
✓ Branch 1 taken 9764419 times.
|
9764497 | if (unlikely(error)) return error; |
| 8568 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9764417 times.
|
9764419 | if (unlikely((error = binlog_log_row(table, buf, nullptr, log_func)))) |
| 8569 | 2 | return error; | |
| 8570 | |||
| 8571 | #ifdef WITH_WSREP | ||
| 8572 | /* With MySQL-8.0 DDL action would result in altering of InnoDB | ||
| 8573 | system table. Logic below should avoid considering alter of InnoDB | ||
| 8574 | system table to increase affected rows. To cover the same, logic | ||
| 8575 | is now expanded to include binlog check. InnoDB flow suppresses | ||
| 8576 | binlogging of the changes that it does to DDL table as part of DDL | ||
| 8577 | execution. */ | ||
| 8578 |
10/12✓ Branch 0 taken 9764417 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4460100 times.
✓ Branch 3 taken 5304317 times.
✓ Branch 4 taken 223260 times.
✓ Branch 5 taken 4236840 times.
✓ Branch 6 taken 135695 times.
✓ Branch 7 taken 87565 times.
✓ Branch 8 taken 135695 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 24368 times.
✓ Branch 11 taken 9740049 times.
|
9900112 | if (WSREP(ha_thd()) && table->s->tmp_table == NO_TMP_TABLE && |
| 8579 |
2/2✓ Branch 0 taken 24368 times.
✓ Branch 1 taken 111327 times.
|
135695 | check_table_binlog_row_based(ha_thd(), table)) { |
| 8580 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24364 times.
|
24368 | if ((error = wsrep_after_row(ha_thd()))) { |
| 8581 | 4 | return error; | |
| 8582 | } | ||
| 8583 | } | ||
| 8584 | #endif /* WITH_WSREP */ | ||
| 8585 | |||
| 8586 | 9764413 | rows_changed++; | |
| 8587 | 9764413 | return 0; | |
| 8588 | } | ||
| 8589 | |||
| 8590 | /** | ||
| 8591 | @brief Offload an update to the storage engine. See handler::fast_update() | ||
| 8592 | for details. | ||
| 8593 | */ | ||
| 8594 | 166135 | int handler::ha_fast_update(THD *thd, mem_root_deque<Item *> &update_fields, | |
| 8595 | mem_root_deque<Item *> &update_values, | ||
| 8596 | Item *conds) { | ||
| 8597 | 166135 | int error = fast_update(thd, update_fields, update_values, conds); | |
| 8598 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 166137 times.
|
166137 | if (error == 0) mark_trx_read_write(); |
| 8599 | 166154 | return error; | |
| 8600 | } | ||
| 8601 | |||
| 8602 | /** | ||
| 8603 | @brief Offload an upsert to the storage engine. See handler::upsert() | ||
| 8604 | for details. | ||
| 8605 | */ | ||
| 8606 | 8567271 | int handler::ha_upsert(THD *thd, mem_root_deque<Item *> &update_fields, | |
| 8607 | mem_root_deque<Item *> &update_values) { | ||
| 8608 | 8567271 | int error = upsert(thd, update_fields, update_values); | |
| 8609 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8567374 times.
|
8567374 | if (error == 0) mark_trx_read_write(); |
| 8610 | 8567502 | return error; | |
| 8611 | } | ||
| 8612 | |||
| 8613 | /** @brief | ||
| 8614 | use_hidden_primary_key() is called in case of an update/delete when | ||
| 8615 | (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined | ||
| 8616 | but we don't have a primary key | ||
| 8617 | */ | ||
| 8618 | ✗ | void handler::use_hidden_primary_key() { | |
| 8619 | /* fallback to use all columns in the table to identify row */ | ||
| 8620 | ✗ | table->use_all_columns(); | |
| 8621 | } | ||
| 8622 | |||
| 8623 | /** | ||
| 8624 | Get an initialized ha_share. | ||
| 8625 | |||
| 8626 | @return Initialized ha_share | ||
| 8627 | @retval NULL ha_share is not yet initialized. | ||
| 8628 | @retval != NULL previous initialized ha_share. | ||
| 8629 | |||
| 8630 | @note | ||
| 8631 | If not a temp table, then LOCK_ha_data must be held. | ||
| 8632 | */ | ||
| 8633 | |||
| 8634 | 159360 | Handler_share *handler::get_ha_share_ptr() { | |
| 8635 |
1/2✓ Branch 0 taken 159360 times.
✗ Branch 1 not taken.
|
159360 | DBUG_TRACE; |
| 8636 |
2/4✓ Branch 0 taken 159360 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 159360 times.
✗ Branch 3 not taken.
|
159360 | assert(ha_share && table_share); |
| 8637 | |||
| 8638 | #ifndef NDEBUG | ||
| 8639 | 159360 | if (table_share->tmp_table == NO_TMP_TABLE) | |
| 8640 | mysql_mutex_assert_owner(&table_share->LOCK_ha_data); | ||
| 8641 | #endif | ||
| 8642 | |||
| 8643 | 159360 | return *ha_share; | |
| 8644 | 159360 | } | |
| 8645 | |||
| 8646 | /** | ||
| 8647 | Set ha_share to be used by all instances of the same table/partition. | ||
| 8648 | |||
| 8649 | @param arg_ha_share Handler_share to be shared. | ||
| 8650 | |||
| 8651 | @note | ||
| 8652 | If not a temp table, then LOCK_ha_data must be held. | ||
| 8653 | */ | ||
| 8654 | |||
| 8655 | 149108 | void handler::set_ha_share_ptr(Handler_share *arg_ha_share) { | |
| 8656 |
1/2✓ Branch 0 taken 149108 times.
✗ Branch 1 not taken.
|
149108 | DBUG_TRACE; |
| 8657 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 149108 times.
|
149108 | assert(ha_share); |
| 8658 | #ifndef NDEBUG | ||
| 8659 | 149108 | if (table_share->tmp_table == NO_TMP_TABLE) | |
| 8660 | mysql_mutex_assert_owner(&table_share->LOCK_ha_data); | ||
| 8661 | #endif | ||
| 8662 | |||
| 8663 | 149108 | *ha_share = arg_ha_share; | |
| 8664 | 149108 | } | |
| 8665 | |||
| 8666 | /** | ||
| 8667 | Take a lock for protecting shared handler data. | ||
| 8668 | */ | ||
| 8669 | |||
| 8670 | 556092 | void handler::lock_shared_ha_data() { | |
| 8671 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 556092 times.
|
556092 | assert(table_share); |
| 8672 |
2/2✓ Branch 0 taken 289076 times.
✓ Branch 1 taken 267016 times.
|
556092 | if (table_share->tmp_table == NO_TMP_TABLE) |
| 8673 | 289076 | mysql_mutex_lock(&table_share->LOCK_ha_data); | |
| 8674 | 556092 | } | |
| 8675 | |||
| 8676 | /** | ||
| 8677 | Release lock for protecting ha_share. | ||
| 8678 | */ | ||
| 8679 | |||
| 8680 | 556092 | void handler::unlock_shared_ha_data() { | |
| 8681 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 556092 times.
|
556092 | assert(table_share); |
| 8682 |
2/2✓ Branch 0 taken 289076 times.
✓ Branch 1 taken 267016 times.
|
556092 | if (table_share->tmp_table == NO_TMP_TABLE) |
| 8683 | 289076 | mysql_mutex_unlock(&table_share->LOCK_ha_data); | |
| 8684 | 556092 | } | |
| 8685 | |||
| 8686 | #ifdef WITH_WSREP | ||
| 8687 | /** | ||
| 8688 | @details | ||
| 8689 | This function makes the storage engine to force the victim transaction | ||
| 8690 | to abort. Currently, only innodb has this functionality, but any SE | ||
| 8691 | implementing the wsrep API should provide this service to support | ||
| 8692 | multi-master operation. | ||
| 8693 | |||
| 8694 | @param bf_thd brute force THD asking for the abort | ||
| 8695 | @param victim_thd victim THD to be aborted | ||
| 8696 | |||
| 8697 | @return | ||
| 8698 | always 0 | ||
| 8699 | */ | ||
| 8700 | |||
| 8701 | 174 | int ha_wsrep_abort_transaction(THD *bf_thd, THD *victim_thd, bool signal) { | |
| 8702 |
1/2✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
|
174 | DBUG_ENTER("ha_wsrep_abort_transaction"); |
| 8703 | |||
| 8704 | // Proceed with abort only if wsrep_on=1 or THD in in RSU | ||
| 8705 |
7/12✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 174 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 172 times.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
|
174 | bool do_abort = WSREP(bf_thd) || wsrep_thd_is_in_rsu(bf_thd); |
| 8706 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 174 times.
|
174 | if (!do_abort) { |
| 8707 | ✗ | DBUG_RETURN(0); | |
| 8708 | } | ||
| 8709 | |||
| 8710 | 174 | handlerton *hton = installed_htons[DB_TYPE_INNODB]; | |
| 8711 |
2/4✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
✗ Branch 3 not taken.
|
174 | if (hton && hton->wsrep_abort_transaction) { |
| 8712 |
1/2✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
|
174 | hton->wsrep_abort_transaction(hton, bf_thd, victim_thd, signal); |
| 8713 | } else { | ||
| 8714 | ✗ | WSREP_WARN("cannot abort InnoDB transaction"); | |
| 8715 | } | ||
| 8716 | |||
| 8717 |
1/2✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
|
174 | DBUG_RETURN(0); |
| 8718 | } | ||
| 8719 | #endif /* WITH_WSREP */ | ||
| 8720 | |||
| 8721 | /** | ||
| 8722 | This structure is a helper structure for passing the length and pointer of | ||
| 8723 | blob space allocated by storage engine. | ||
| 8724 | */ | ||
| 8725 | struct blob_len_ptr { | ||
| 8726 | uint length; // length of the blob | ||
| 8727 | uchar *ptr; // pointer of the value | ||
| 8728 | }; | ||
| 8729 | |||
| 8730 | /** | ||
| 8731 | Get the blob length and pointer of allocated space from the record buffer. | ||
| 8732 | |||
| 8733 | During evaluating the blob virtual generated columns, the blob space will | ||
| 8734 | be allocated by server. In order to keep the blob data after the table is | ||
| 8735 | closed, we need write the data into a specified space allocated by storage | ||
| 8736 | engine. Here, we have to extract the space pointer and length from the | ||
| 8737 | record buffer. | ||
| 8738 | After we get the value of virtual generated columns, copy the data into | ||
| 8739 | the specified space and store it in the record buffer (@see copy_blob_data()). | ||
| 8740 | |||
| 8741 | @param table the pointer of table | ||
| 8742 | @param fields bitmap of field index of evaluated | ||
| 8743 | generated column | ||
| 8744 | @param[out] blob_len_ptr_array an array to record the length and pointer | ||
| 8745 | of allocated space by storage engine. | ||
| 8746 | @note The caller should provide the blob_len_ptr_array with a size of | ||
| 8747 | MAX_FIELDS. | ||
| 8748 | */ | ||
| 8749 | |||
| 8750 | ✗ | static void extract_blob_space_and_length_from_record_buff( | |
| 8751 | const TABLE *table, const MY_BITMAP *const fields, | ||
| 8752 | blob_len_ptr *blob_len_ptr_array) { | ||
| 8753 | ✗ | int num = 0; | |
| 8754 | ✗ | for (Field **vfield = table->vfield; *vfield; vfield++) { | |
| 8755 | // Check if this field should be included | ||
| 8756 | ✗ | if (bitmap_is_set(fields, (*vfield)->field_index()) && | |
| 8757 | ✗ | (*vfield)->is_virtual_gcol() && (*vfield)->type() == MYSQL_TYPE_BLOB) { | |
| 8758 | ✗ | auto field = down_cast<Field_blob *>(*vfield); | |
| 8759 | ✗ | blob_len_ptr_array[num].length = field->data_length(); | |
| 8760 | // TODO: The following check is only for Innodb. | ||
| 8761 | ✗ | assert(blob_len_ptr_array[num].length == 255 || | |
| 8762 | blob_len_ptr_array[num].length == 768 || | ||
| 8763 | blob_len_ptr_array[num].length == 3073); | ||
| 8764 | |||
| 8765 | ✗ | blob_len_ptr_array[num].ptr = field->get_blob_data(); | |
| 8766 | |||
| 8767 | // Let server allocate the space for BLOB virtual generated columns | ||
| 8768 | ✗ | field->reset(); | |
| 8769 | |||
| 8770 | ✗ | num++; | |
| 8771 | ✗ | assert(num <= MAX_FIELDS); | |
| 8772 | } | ||
| 8773 | } | ||
| 8774 | } | ||
| 8775 | |||
| 8776 | /** | ||
| 8777 | Copy the value of BLOB virtual generated columns into the space allocated | ||
| 8778 | by storage engine. | ||
| 8779 | |||
| 8780 | This is because the table is closed after evaluating the value. In order to | ||
| 8781 | keep the BLOB value after the table is closed, we have to copy the value into | ||
| 8782 | the place where storage engine prepares for. | ||
| 8783 | |||
| 8784 | @param table pointer of the table to be operated on | ||
| 8785 | @param fields bitmap of field index of evaluated generated column | ||
| 8786 | @param blob_len_ptr_array array of length and pointer of allocated space by | ||
| 8787 | storage engine. | ||
| 8788 | */ | ||
| 8789 | |||
| 8790 | ✗ | static void copy_blob_data(const TABLE *table, const MY_BITMAP *const fields, | |
| 8791 | blob_len_ptr *blob_len_ptr_array) { | ||
| 8792 | ✗ | uint num = 0; | |
| 8793 | ✗ | for (Field **vfield = table->vfield; *vfield; vfield++) { | |
| 8794 | // Check if this field should be included | ||
| 8795 | ✗ | if (bitmap_is_set(fields, (*vfield)->field_index()) && | |
| 8796 | ✗ | (*vfield)->is_virtual_gcol() && (*vfield)->type() == MYSQL_TYPE_BLOB) { | |
| 8797 | ✗ | assert(blob_len_ptr_array[num].length > 0); | |
| 8798 | ✗ | assert(blob_len_ptr_array[num].ptr != nullptr); | |
| 8799 | |||
| 8800 | /* | ||
| 8801 | Only copy as much of the blob as the storage engine has | ||
| 8802 | allocated space for. This is sufficient since the only use of the | ||
| 8803 | blob in the storage engine is for using a prefix of it in a | ||
| 8804 | secondary index. | ||
| 8805 | */ | ||
| 8806 | ✗ | uint length = (*vfield)->data_length(); | |
| 8807 | ✗ | const uint alloc_len = blob_len_ptr_array[num].length; | |
| 8808 | ✗ | length = length > alloc_len ? alloc_len : length; | |
| 8809 | |||
| 8810 | ✗ | Field_blob *blob_field = down_cast<Field_blob *>(*vfield); | |
| 8811 | ✗ | memcpy(blob_len_ptr_array[num].ptr, blob_field->get_blob_data(), length); | |
| 8812 | ✗ | blob_field->store_in_allocated_space( | |
| 8813 | ✗ | pointer_cast<char *>(blob_len_ptr_array[num].ptr), length); | |
| 8814 | ✗ | num++; | |
| 8815 | ✗ | assert(num <= MAX_FIELDS); | |
| 8816 | } | ||
| 8817 | } | ||
| 8818 | } | ||
| 8819 | |||
| 8820 | 88361831 | bool handler::is_using_prohibited_gap_locks( | |
| 8821 | TABLE *table, bool using_full_primary_key) const noexcept { | ||
| 8822 | 88361831 | const THD *thd = table->in_use; | |
| 8823 | 88361831 | const thr_lock_type lock_type = table->reginfo.lock_type; | |
| 8824 | |||
| 8825 |
4/4✓ Branch 0 taken 35617915 times.
✓ Branch 1 taken 13303798 times.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 35617717 times.
|
48921693 | if (!using_full_primary_key && has_transactions() && !has_gap_locks() && |
| 8826 |
3/4✓ Branch 0 taken 136 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 136 times.
✗ Branch 3 not taken.
|
126 | thd_tx_isolation(thd) >= ISO_REPEATABLE_READ && !thd->rli_slave && |
| 8827 |
4/6✓ Branch 0 taken 107 times.
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 107 times.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
|
136 | (thd->lex->table_count >= 2 || thd->in_multi_stmt_transaction_mode()) && |
| 8828 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | (lock_type >= TL_WRITE_ALLOW_WRITE || |
| 8829 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | lock_type == TL_READ_WITH_SHARED_LOCKS || |
| 8830 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | lock_type == TL_READ_NO_INSERT || |
| 8831 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 27 times.
|
29 | (lock_type != TL_IGNORE && thd->lex->sql_command != SQLCOM_SELECT)) && |
| 8832 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | thd->lex->sql_command != SQLCOM_ALTER_TABLE && |
| 8833 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | thd->lex->sql_command != SQLCOM_CREATE_INDEX && |
| 8834 |
5/6✓ Branch 0 taken 48921693 times.
✓ Branch 1 taken 39440138 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 88361790 times.
|
137283487 | thd->lex->sql_command != SQLCOM_CHECK && |
| 8835 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | thd->lex->sql_command != SQLCOM_OPTIMIZE) { |
| 8836 | 2 | my_printf_error(ER_UNKNOWN_ERROR, | |
| 8837 | "Using Gap Lock without full unique key in multi-table " | ||
| 8838 | "or multi-statement transactions is not " | ||
| 8839 | "allowed. You need to either rewrite queries to use " | ||
| 8840 | "all unique key columns in WHERE equal conditions, or " | ||
| 8841 | "rewrite to single-table, single-statement " | ||
| 8842 | "transaction. Query: %s", | ||
| 8843 | 2 | MYF(0), thd->query().str); | |
| 8844 | 2 | return true; | |
| 8845 | } | ||
| 8846 | 88361790 | return false; | |
| 8847 | } | ||
| 8848 | |||
| 8849 | /* | ||
| 8850 | Evaluate generated column's value. This is an internal helper reserved for | ||
| 8851 | handler::my_eval_gcolumn_expr(). | ||
| 8852 | |||
| 8853 | @param thd pointer of THD | ||
| 8854 | @param table The pointer of table where evaluated generated | ||
| 8855 | columns are in | ||
| 8856 | @param fields bitmap of field index of evaluated generated column | ||
| 8857 | @param[in,out] record record buff of base columns generated column depends. | ||
| 8858 | After calling this function, it will be used to return | ||
| 8859 | the value of generated column. | ||
| 8860 | @param in_purge whether the function is called by purge thread | ||
| 8861 | |||
| 8862 | @return true in case of error, false otherwise. | ||
| 8863 | */ | ||
| 8864 | |||
| 8865 | 29708 | static bool my_eval_gcolumn_expr_helper(THD *thd, TABLE *table, | |
| 8866 | const MY_BITMAP *const fields, | ||
| 8867 | uchar *record, bool in_purge, | ||
| 8868 | const char **mv_data_ptr, | ||
| 8869 | ulong *mv_length) { | ||
| 8870 |
1/2✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
|
29708 | DBUG_TRACE; |
| 8871 |
2/4✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29708 times.
✗ Branch 3 not taken.
|
29708 | assert(table && table->vfield); |
| 8872 |
2/4✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29708 times.
|
29708 | assert(!thd->is_error()); |
| 8873 | |||
| 8874 | 29708 | uchar *old_buf = table->record[0]; | |
| 8875 |
1/2✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
|
29708 | repoint_field_to_record(table, old_buf, record); |
| 8876 | |||
| 8877 | blob_len_ptr blob_len_ptr_array[MAX_FIELDS]; | ||
| 8878 | |||
| 8879 | /* | ||
| 8880 | If it's purge thread, we need get the space allocated by storage engine | ||
| 8881 | for blob. | ||
| 8882 | */ | ||
| 8883 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29708 times.
|
29708 | if (in_purge) |
| 8884 | ✗ | extract_blob_space_and_length_from_record_buff(table, fields, | |
| 8885 | blob_len_ptr_array); | ||
| 8886 | |||
| 8887 | 29708 | bool res = false; | |
| 8888 | 29708 | Field *mv_field = nullptr; | |
| 8889 | 29708 | MY_BITMAP fields_to_evaluate; | |
| 8890 | my_bitmap_map bitbuf[bitmap_buffer_size(MAX_FIELDS) / sizeof(my_bitmap_map)]; | ||
| 8891 |
1/2✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
|
29708 | bitmap_init(&fields_to_evaluate, bitbuf, table->s->fields); |
| 8892 | 29708 | bitmap_set_all(&fields_to_evaluate); | |
| 8893 |
1/2✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
|
29708 | bitmap_intersect(&fields_to_evaluate, fields); |
| 8894 | /* | ||
| 8895 | In addition to evaluating the value for the columns requested by | ||
| 8896 | the caller we also need to evaluate any virtual columns that these | ||
| 8897 | depend on. | ||
| 8898 | This loop goes through the columns that should be evaluated and | ||
| 8899 | adds all the base columns. If the base column is virtual, it has | ||
| 8900 | to be evaluated. | ||
| 8901 | */ | ||
| 8902 |
2/2✓ Branch 0 taken 37750 times.
✓ Branch 1 taken 29708 times.
|
67458 | for (Field **vfield_ptr = table->vfield; *vfield_ptr; vfield_ptr++) { |
| 8903 | 37750 | Field *field = *vfield_ptr; | |
| 8904 | // Validate that the field number is less than the bit map size | ||
| 8905 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37750 times.
|
37750 | assert(field->field_index() < fields->n_bits); |
| 8906 | |||
| 8907 |
2/2✓ Branch 0 taken 29708 times.
✓ Branch 1 taken 8042 times.
|
37750 | if (bitmap_is_set(fields, field->field_index())) { |
| 8908 |
1/2✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
|
29708 | bitmap_union(&fields_to_evaluate, &field->gcol_info->base_columns_map); |
| 8909 |
3/4✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25433 times.
✓ Branch 3 taken 4275 times.
|
29708 | if (field->is_array()) { |
| 8910 | 25433 | mv_field = field; | |
| 8911 | // Backup current value and use dedicated temporary buffer | ||
| 8912 |
2/4✓ Branch 0 taken 25433 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 25433 times.
|
25433 | if ((down_cast<Field_blob *>(field))->backup_blob_field()) return true; |
| 8913 | } | ||
| 8914 | } | ||
| 8915 | } | ||
| 8916 | |||
| 8917 | /* | ||
| 8918 | Evaluate all requested columns and all base columns these depends | ||
| 8919 | on that are virtual. | ||
| 8920 | |||
| 8921 | This function is called by the storage engine, which may request to | ||
| 8922 | evaluate more generated columns than read_set/write_set says. | ||
| 8923 | For example, InnoDB's row_sel_sec_rec_is_for_clust_rec() reads the full | ||
| 8924 | record from the clustered index and asks us to compute generated columns | ||
| 8925 | that match key fields in the used secondary index. So we trust that the | ||
| 8926 | engine has filled all base columns necessary to requested computations, | ||
| 8927 | and we ignore read_set/write_set. | ||
| 8928 | */ | ||
| 8929 | |||
| 8930 | my_bitmap_map *old_maps[2]; | ||
| 8931 | 29708 | dbug_tmp_use_all_columns(table, old_maps, table->read_set, table->write_set); | |
| 8932 | |||
| 8933 |
2/2✓ Branch 0 taken 37750 times.
✓ Branch 1 taken 29674 times.
|
67424 | for (Field **vfield_ptr = table->vfield; *vfield_ptr; vfield_ptr++) { |
| 8934 | 37750 | Field *field = *vfield_ptr; | |
| 8935 | |||
| 8936 | // Check if we should evaluate this field | ||
| 8937 |
5/6✓ Branch 0 taken 29714 times.
✓ Branch 1 taken 8036 times.
✓ Branch 2 taken 29714 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 29714 times.
✓ Branch 5 taken 8036 times.
|
67464 | if (bitmap_is_set(&fields_to_evaluate, field->field_index()) && |
| 8938 | 29714 | field->is_virtual_gcol()) { | |
| 8939 |
2/4✓ Branch 0 taken 29714 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29714 times.
✗ Branch 3 not taken.
|
29714 | assert(field->gcol_info && field->gcol_info->expr_item->fixed); |
| 8940 | |||
| 8941 | const type_conversion_status save_in_field_status = | ||
| 8942 |
1/2✓ Branch 0 taken 29714 times.
✗ Branch 1 not taken.
|
29714 | field->gcol_info->expr_item->save_in_field(field, false); |
| 8943 |
4/6✓ Branch 0 taken 29714 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 29680 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 34 times.
|
29714 | assert(!thd->is_error() || save_in_field_status != TYPE_OK); |
| 8944 | |||
| 8945 | /* | ||
| 8946 | save_in_field() may return non-zero even if there was no | ||
| 8947 | error. This happens if a warning is raised, such as an | ||
| 8948 | out-of-range warning when converting the result to the target | ||
| 8949 | type of the virtual column. We should stop only if the | ||
| 8950 | non-zero return value was caused by an actual error. | ||
| 8951 | */ | ||
| 8952 |
7/8✓ Branch 0 taken 41 times.
✓ Branch 1 taken 29673 times.
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 34 times.
✓ Branch 7 taken 29680 times.
|
29714 | if (save_in_field_status != TYPE_OK && thd->is_error()) { |
| 8953 | 34 | res = true; | |
| 8954 | 34 | break; | |
| 8955 | } | ||
| 8956 | } | ||
| 8957 | } | ||
| 8958 | |||
| 8959 | 29708 | dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_maps); | |
| 8960 | |||
| 8961 | /* | ||
| 8962 | If it's a purge thread, we need copy the blob data into specified place | ||
| 8963 | allocated by storage engine so that the blob data still can be accessed | ||
| 8964 | after table is closed. | ||
| 8965 | */ | ||
| 8966 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 29708 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
29708 | if (in_purge) copy_blob_data(table, fields, blob_len_ptr_array); |
| 8967 | |||
| 8968 |
2/2✓ Branch 0 taken 25433 times.
✓ Branch 1 taken 4275 times.
|
29708 | if (mv_field) { |
| 8969 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25433 times.
|
25433 | assert(mv_data_ptr); |
| 8970 | 25433 | Field_json *fld = down_cast<Field_json *>(mv_field); | |
| 8971 | // Save calculated value | ||
| 8972 |
1/2✓ Branch 0 taken 25433 times.
✗ Branch 1 not taken.
|
25433 | *mv_data_ptr = fld->get_binary(); |
| 8973 |
1/2✓ Branch 0 taken 25433 times.
✗ Branch 1 not taken.
|
25433 | *mv_length = fld->data_length(); |
| 8974 | // Restore original value | ||
| 8975 |
1/2✓ Branch 0 taken 25433 times.
✗ Branch 1 not taken.
|
25433 | (fld)->restore_blob_backup(); |
| 8976 | } | ||
| 8977 | |||
| 8978 |
1/2✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
|
29708 | repoint_field_to_record(table, record, old_buf); |
| 8979 | 29708 | return res; | |
| 8980 | 29708 | } | |
| 8981 | |||
| 8982 | // Set se_private_id and se_private_data during upgrade | ||
| 8983 | 5044 | bool handler::ha_upgrade_table(THD *thd, const char *dbname, | |
| 8984 | const char *table_name, dd::Table *dd_table, | ||
| 8985 | TABLE *table_arg) { | ||
| 8986 | 5044 | table = table_arg; | |
| 8987 | 5044 | return upgrade_table(thd, dbname, table_name, dd_table); | |
| 8988 | } | ||
| 8989 | |||
| 8990 | /** | ||
| 8991 | Callback to allow InnoDB to prepare a template for generated | ||
| 8992 | column processing. This function will open the table without | ||
| 8993 | opening in the engine and call the provided function with | ||
| 8994 | the TABLE object made. The function will then close the TABLE. | ||
| 8995 | |||
| 8996 | @param thd Thread handle | ||
| 8997 | @param db_name Name of database containing the table | ||
| 8998 | @param table_name Name of table to open | ||
| 8999 | @param myc InnoDB function to call for processing TABLE | ||
| 9000 | @param ib_table Argument for InnoDB function | ||
| 9001 | |||
| 9002 | @return true in case of error, false otherwise. | ||
| 9003 | */ | ||
| 9004 | |||
| 9005 | 2 | bool handler::my_prepare_gcolumn_template(THD *thd, const char *db_name, | |
| 9006 | const char *table_name, | ||
| 9007 | my_gcolumn_template_callback_t myc, | ||
| 9008 | void *ib_table) { | ||
| 9009 | 2 | bool rc = true; | |
| 9010 | 2 | Temp_table_handle tblhdl; | |
| 9011 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | TABLE *table = tblhdl.open(thd, db_name, table_name); |
| 9012 | |||
| 9013 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (table) { |
| 9014 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | myc(table, ib_table); |
| 9015 | 2 | rc = false; | |
| 9016 | } | ||
| 9017 | 2 | return rc; | |
| 9018 | 2 | } | |
| 9019 | |||
| 9020 | /** | ||
| 9021 | Callback for generated columns processing. Will open the table, in the | ||
| 9022 | server *only*, and call my_eval_gcolumn_expr_helper() to do the actual | ||
| 9023 | processing. This function is a variant of the other | ||
| 9024 | handler::my_eval_gcolumn_expr() but is intended for use when no TABLE | ||
| 9025 | object already exists - e.g. from purge threads. | ||
| 9026 | |||
| 9027 | Note! The call to open_table_uncached() must be made with the second-to-last | ||
| 9028 | argument (open_in_engine) set to false. Failing to do so will cause | ||
| 9029 | deadlocks and incorrect behavior. | ||
| 9030 | |||
| 9031 | @param thd thread handle | ||
| 9032 | @param db_name database containing the table to open | ||
| 9033 | @param table_name name of table to open | ||
| 9034 | @param fields bitmap of field index of evaluated generated column | ||
| 9035 | @param record record buffer | ||
| 9036 | @param[out] mv_data_ptr For a typed array field in this arg the pointer | ||
| 9037 | to its value is returned | ||
| 9038 | @param[out] mv_length Length of the value above | ||
| 9039 | |||
| 9040 | @return true in case of error, false otherwise. | ||
| 9041 | */ | ||
| 9042 | |||
| 9043 | ✗ | bool handler::my_eval_gcolumn_expr_with_open(THD *thd, const char *db_name, | |
| 9044 | const char *table_name, | ||
| 9045 | const MY_BITMAP *const fields, | ||
| 9046 | uchar *record, | ||
| 9047 | const char **mv_data_ptr, | ||
| 9048 | ulong *mv_length) { | ||
| 9049 | ✗ | bool retval = true; | |
| 9050 | ✗ | Temp_table_handle tblhdl; | |
| 9051 | ✗ | TABLE *table = tblhdl.open(thd, db_name, table_name); | |
| 9052 | |||
| 9053 | ✗ | if (table) { | |
| 9054 | ✗ | retval = my_eval_gcolumn_expr_helper(thd, table, fields, record, true, | |
| 9055 | mv_data_ptr, mv_length); | ||
| 9056 | } | ||
| 9057 | |||
| 9058 | ✗ | return retval; | |
| 9059 | } | ||
| 9060 | |||
| 9061 | 29708 | bool handler::my_eval_gcolumn_expr(THD *thd, TABLE *table, | |
| 9062 | const MY_BITMAP *const fields, uchar *record, | ||
| 9063 | const char **mv_data_ptr, ulong *mv_length) { | ||
| 9064 |
1/2✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
|
29708 | DBUG_TRACE; |
| 9065 | |||
| 9066 |
1/2✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
|
29708 | const bool res = my_eval_gcolumn_expr_helper(thd, table, fields, record, |
| 9067 | false, mv_data_ptr, mv_length); | ||
| 9068 | 29708 | return res; | |
| 9069 | 29708 | } | |
| 9070 | |||
| 9071 | 1448 | bool handler::filter_dup_records() { | |
| 9072 |
2/4✓ Branch 0 taken 1448 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1448 times.
✗ Branch 3 not taken.
|
1448 | assert(inited == INDEX && m_unique); |
| 9073 | 1448 | position(table->record[0]); | |
| 9074 | 1448 | return m_unique->unique_add(ref); | |
| 9075 | } | ||
| 9076 | |||
| 9077 | 738293326 | int handler::ha_extra(enum ha_extra_function operation) { | |
| 9078 |
2/2✓ Branch 0 taken 506 times.
✓ Branch 1 taken 738292820 times.
|
738293326 | if (operation == HA_EXTRA_ENABLE_UNIQUE_RECORD_FILTER) { |
| 9079 | // This operation should be called only for active multi-valued index | ||
| 9080 |
2/4✓ Branch 0 taken 506 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 506 times.
✗ Branch 3 not taken.
|
506 | assert(inited == INDEX && |
| 9081 | (table->key_info[active_index].flags & HA_MULTI_VALUED_KEY)); | ||
| 9082 | // This unique filter uses only row id to weed out duplicates. Due to that | ||
| 9083 | // it will work with any active index. | ||
| 9084 |
3/4✓ Branch 0 taken 500 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 506 times.
|
1006 | if (!m_unique && |
| 9085 |
2/4✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 500 times.
✗ Branch 3 not taken.
|
500 | (!(m_unique = new (*THR_MALLOC) Unique_on_insert(ref_length)) || |
| 9086 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 500 times.
|
500 | m_unique->init())) { |
| 9087 | /* purecov: begin inspected */ | ||
| 9088 | ✗ | destroy(m_unique); | |
| 9089 | ✗ | return HA_ERR_OUT_OF_MEM; | |
| 9090 | /* purecov: end */ | ||
| 9091 | } | ||
| 9092 | 506 | m_unique->reset(true); | |
| 9093 | 506 | return 0; | |
| 9094 |
2/2✓ Branch 0 taken 580 times.
✓ Branch 1 taken 738292240 times.
|
738292820 | } else if (operation == HA_EXTRA_DISABLE_UNIQUE_RECORD_FILTER) { |
| 9095 |
2/2✓ Branch 0 taken 448 times.
✓ Branch 1 taken 132 times.
|
580 | if (m_unique) { |
| 9096 | 448 | m_unique->cleanup(); | |
| 9097 | 448 | destroy(m_unique); | |
| 9098 | 448 | m_unique = nullptr; | |
| 9099 | } | ||
| 9100 | } | ||
| 9101 | 738292820 | return extra(operation); | |
| 9102 | } | ||
| 9103 | |||
| 9104 | 204 | TABLE *Temp_table_handle::open(THD *thd, const char *db_name, | |
| 9105 | const char *table_name) { | ||
| 9106 | char path[FN_REFLEN + 1]; | ||
| 9107 | bool was_truncated; | ||
| 9108 |
1/2✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
|
204 | build_table_filename(path, sizeof(path) - 1 - reg_ext_length, db_name, |
| 9109 | table_name, "", 0, &was_truncated); | ||
| 9110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
|
204 | assert(!was_truncated); |
| 9111 | |||
| 9112 | 204 | MDL_request table_request; | |
| 9113 |
1/2✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
|
204 | MDL_REQUEST_INIT(&table_request, MDL_key::TABLE, db_name, table_name, |
| 9114 | MDL_SHARED, MDL_TRANSACTION); | ||
| 9115 | |||
| 9116 |
2/4✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 204 times.
|
204 | if (thd->mdl_context.acquire_lock(&table_request, |
| 9117 | thd->variables.lock_wait_timeout)) { | ||
| 9118 | ✗ | return nullptr; | |
| 9119 | } | ||
| 9120 | |||
| 9121 | { | ||
| 9122 |
1/2✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
|
204 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 9123 | 204 | const dd::Table *tab_obj = nullptr; | |
| 9124 |
4/8✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 204 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 204 times.
|
204 | if (thd->dd_client()->acquire(db_name, table_name, &tab_obj)) |
| 9125 | ✗ | return nullptr; | |
| 9126 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
|
204 | assert(tab_obj); |
| 9127 |
1/2✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
|
204 | table = open_table_uncached(thd, path, db_name, table_name, false, false, |
| 9128 | *tab_obj); | ||
| 9129 |
1/2✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
|
204 | } |
| 9130 | 204 | return table; | |
| 9131 | } | ||
| 9132 | |||
| 9133 | 29710 | Temp_table_handle::~Temp_table_handle() { | |
| 9134 |
2/2✓ Branch 0 taken 204 times.
✓ Branch 1 taken 29506 times.
|
29710 | if (table != nullptr) { |
| 9135 | 204 | intern_close_table(table); | |
| 9136 | } | ||
| 9137 | 29710 | } | |
| 9138 | |||
| 9139 | /** | ||
| 9140 | Auxiliary structure for passing information to notify_*_helper() | ||
| 9141 | functions. | ||
| 9142 | */ | ||
| 9143 | |||
| 9144 | struct HTON_NOTIFY_PARAMS { | ||
| 9145 | 7173364 | HTON_NOTIFY_PARAMS(const MDL_key *mdl_key, ha_notification_type mdl_type) | |
| 9146 | 7173364 | : key(mdl_key), | |
| 9147 | 7173364 | notification_type(mdl_type), | |
| 9148 | 7173364 | some_htons_were_notified(false), | |
| 9149 | 7173364 | victimized(false) {} | |
| 9150 | |||
| 9151 | const MDL_key *key; | ||
| 9152 | const ha_notification_type notification_type; | ||
| 9153 | bool some_htons_were_notified; | ||
| 9154 | bool victimized; | ||
| 9155 | }; | ||
| 9156 | |||
| 9157 | 58539471 | static bool notify_exclusive_mdl_helper(THD *thd, plugin_ref plugin, | |
| 9158 | void *arg) { | ||
| 9159 | 58539471 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 9160 |
3/4✓ Branch 0 taken 58411665 times.
✓ Branch 1 taken 127806 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58411665 times.
|
58539471 | if (hton->state == SHOW_OPTION_YES && hton->notify_exclusive_mdl) { |
| 9161 | ✗ | HTON_NOTIFY_PARAMS *params = reinterpret_cast<HTON_NOTIFY_PARAMS *>(arg); | |
| 9162 | |||
| 9163 | ✗ | if (hton->notify_exclusive_mdl(thd, params->key, params->notification_type, | |
| 9164 | ¶ms->victimized)) { | ||
| 9165 | // Ignore failures from post event notification. | ||
| 9166 | ✗ | if (params->notification_type == HA_NOTIFY_PRE_EVENT) return true; | |
| 9167 | } else | ||
| 9168 | ✗ | params->some_htons_were_notified = true; | |
| 9169 | } | ||
| 9170 | 58539471 | return false; | |
| 9171 | } | ||
| 9172 | |||
| 9173 | /** | ||
| 9174 | Notify/get permission from all interested storage engines before | ||
| 9175 | acquisition or after release of exclusive metadata lock on object | ||
| 9176 | represented by key. | ||
| 9177 | |||
| 9178 | @param thd Thread context. | ||
| 9179 | @param mdl_key MDL key identifying object on which exclusive | ||
| 9180 | lock is to be acquired/was released. | ||
| 9181 | @param notification_type Indicates whether this is pre-acquire or | ||
| 9182 | post-release notification. | ||
| 9183 | @param victimized 'true' if locking failed as we were selected | ||
| 9184 | as a victim in order to avoid possible deadlocks. | ||
| 9185 | |||
| 9186 | See @sa handlerton::notify_exclusive_mdl for details about | ||
| 9187 | calling convention and error reporting. | ||
| 9188 | |||
| 9189 | @return False - if notification was successful/lock can be acquired, | ||
| 9190 | True - if it has failed/lock should not be acquired. | ||
| 9191 | */ | ||
| 9192 | |||
| 9193 | 6964775 | bool ha_notify_exclusive_mdl(THD *thd, const MDL_key *mdl_key, | |
| 9194 | ha_notification_type notification_type, | ||
| 9195 | bool *victimized) { | ||
| 9196 | 6964775 | HTON_NOTIFY_PARAMS params(mdl_key, notification_type); | |
| 9197 | 6964775 | *victimized = false; | |
| 9198 |
2/4✓ Branch 0 taken 6964776 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6964776 times.
|
6964775 | if (plugin_foreach(thd, notify_exclusive_mdl_helper, |
| 9199 | MYSQL_STORAGE_ENGINE_PLUGIN, ¶ms)) { | ||
| 9200 | ✗ | *victimized = params.victimized; | |
| 9201 | /* | ||
| 9202 | If some SE hasn't given its permission to acquire lock and some SEs | ||
| 9203 | has given their permissions, we need to notify the latter group about | ||
| 9204 | failed lock acquisition. We do this by calling post-release notification | ||
| 9205 | for all interested SEs unconditionally. | ||
| 9206 | */ | ||
| 9207 | ✗ | if (notification_type == HA_NOTIFY_PRE_EVENT && | |
| 9208 | ✗ | params.some_htons_were_notified) { | |
| 9209 | ✗ | HTON_NOTIFY_PARAMS rollback_params(mdl_key, HA_NOTIFY_POST_EVENT); | |
| 9210 | ✗ | (void)plugin_foreach(thd, notify_exclusive_mdl_helper, | |
| 9211 | MYSQL_STORAGE_ENGINE_PLUGIN, &rollback_params); | ||
| 9212 | } | ||
| 9213 | ✗ | return true; | |
| 9214 | } | ||
| 9215 | 6964776 | return false; | |
| 9216 | } | ||
| 9217 | |||
| 9218 | 2294631 | static bool notify_alter_table_helper(THD *thd, plugin_ref plugin, void *arg) { | |
| 9219 | 2294631 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 9220 |
3/4✓ Branch 0 taken 2284814 times.
✓ Branch 1 taken 9817 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2284814 times.
|
2294631 | if (hton->state == SHOW_OPTION_YES && hton->notify_alter_table) { |
| 9221 | ✗ | HTON_NOTIFY_PARAMS *params = reinterpret_cast<HTON_NOTIFY_PARAMS *>(arg); | |
| 9222 | |||
| 9223 | ✗ | if (hton->notify_alter_table(thd, params->key, params->notification_type)) { | |
| 9224 | // Ignore failures from post event notification. | ||
| 9225 | ✗ | if (params->notification_type == HA_NOTIFY_PRE_EVENT) return true; | |
| 9226 | } else | ||
| 9227 | ✗ | params->some_htons_were_notified = true; | |
| 9228 | } | ||
| 9229 | 2294631 | return false; | |
| 9230 | } | ||
| 9231 | |||
| 9232 | /** | ||
| 9233 | Notify/get permission from all interested storage engines before | ||
| 9234 | or after executed ALTER TABLE on the table identified by key. | ||
| 9235 | |||
| 9236 | @param thd Thread context. | ||
| 9237 | @param mdl_key MDL key identifying table. | ||
| 9238 | @param notification_type Indicates whether this is pre-ALTER or | ||
| 9239 | post-ALTER notification. | ||
| 9240 | |||
| 9241 | See @sa handlerton::notify_alter_table for rationale, | ||
| 9242 | details about calling convention and error reporting. | ||
| 9243 | |||
| 9244 | @return False - if notification was successful/ALTER TABLE can | ||
| 9245 | proceed. | ||
| 9246 | True - if it has failed/ALTER TABLE should fail. | ||
| 9247 | */ | ||
| 9248 | |||
| 9249 | 208589 | bool ha_notify_alter_table(THD *thd, const MDL_key *mdl_key, | |
| 9250 | ha_notification_type notification_type) { | ||
| 9251 | 208589 | HTON_NOTIFY_PARAMS params(mdl_key, notification_type); | |
| 9252 | |||
| 9253 |
2/4✓ Branch 0 taken 208589 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 208589 times.
|
208589 | if (plugin_foreach(thd, notify_alter_table_helper, |
| 9254 | MYSQL_STORAGE_ENGINE_PLUGIN, ¶ms)) { | ||
| 9255 | /* | ||
| 9256 | If some SE hasn't given its permission to do ALTER TABLE and some SEs | ||
| 9257 | has given their permissions, we need to notify the latter group about | ||
| 9258 | failed attemopt. We do this by calling post-ALTER TABLE notification | ||
| 9259 | for all interested SEs unconditionally. | ||
| 9260 | */ | ||
| 9261 | ✗ | if (notification_type == HA_NOTIFY_PRE_EVENT && | |
| 9262 | ✗ | params.some_htons_were_notified) { | |
| 9263 | ✗ | HTON_NOTIFY_PARAMS rollback_params(mdl_key, HA_NOTIFY_POST_EVENT); | |
| 9264 | ✗ | (void)plugin_foreach(thd, notify_alter_table_helper, | |
| 9265 | MYSQL_STORAGE_ENGINE_PLUGIN, &rollback_params); | ||
| 9266 | } | ||
| 9267 | ✗ | return true; | |
| 9268 | } | ||
| 9269 | 208589 | return false; | |
| 9270 | } | ||
| 9271 | |||
| 9272 | /** | ||
| 9273 | Set the transaction isolation level for the next transaction and update | ||
| 9274 | session tracker information about the transaction isolation level. | ||
| 9275 | |||
| 9276 | @param thd THD session setting the tx_isolation. | ||
| 9277 | @param tx_isolation The isolation level to be set. | ||
| 9278 | @param one_shot True if the isolation level should be restored to | ||
| 9279 | session default after finishing the transaction. | ||
| 9280 | */ | ||
| 9281 | 131551 | bool set_tx_isolation(THD *thd, enum_tx_isolation tx_isolation, bool one_shot) { | |
| 9282 | 131551 | TX_TRACKER_GET(tst); | |
| 9283 | |||
| 9284 |
2/2✓ Branch 0 taken 131546 times.
✓ Branch 1 taken 12 times.
|
131558 | if (thd->variables.session_track_transaction_info <= TX_TRACK_NONE) |
| 9285 | 131546 | tst = nullptr; | |
| 9286 | |||
| 9287 | 131558 | thd->tx_isolation = tx_isolation; | |
| 9288 | |||
| 9289 |
2/2✓ Branch 0 taken 131034 times.
✓ Branch 1 taken 524 times.
|
131558 | if (one_shot) { |
| 9290 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 131034 times.
|
131034 | assert(!thd->in_active_multi_stmt_transaction()); |
| 9291 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 131034 times.
|
131034 | assert(!thd->in_sub_stmt); |
| 9292 | enum enum_tx_isol_level l; | ||
| 9293 |
5/5✓ Branch 0 taken 39 times.
✓ Branch 1 taken 130863 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 96 times.
✓ Branch 4 taken 1 times.
|
131034 | switch (thd->tx_isolation) { |
| 9294 | 39 | case ISO_READ_UNCOMMITTED: | |
| 9295 | 39 | l = TX_ISOL_UNCOMMITTED; | |
| 9296 | 39 | break; | |
| 9297 | 130863 | case ISO_READ_COMMITTED: | |
| 9298 | 130863 | l = TX_ISOL_COMMITTED; | |
| 9299 | 130863 | break; | |
| 9300 | 35 | case ISO_REPEATABLE_READ: | |
| 9301 | 35 | l = TX_ISOL_REPEATABLE; | |
| 9302 | 35 | break; | |
| 9303 | 96 | case ISO_SERIALIZABLE: | |
| 9304 | 96 | l = TX_ISOL_SERIALIZABLE; | |
| 9305 | 96 | break; | |
| 9306 | 1 | default: | |
| 9307 | 1 | assert(0); | |
| 9308 | return true; | ||
| 9309 | } | ||
| 9310 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 131024 times.
|
131033 | if (tst) tst->set_isol_level(thd, l); |
| 9311 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 521 times.
|
524 | } else if (tst) { |
| 9312 | 3 | tst->set_isol_level(thd, TX_ISOL_INHERIT); | |
| 9313 | } | ||
| 9314 | 131558 | return false; | |
| 9315 | } | ||
| 9316 | |||
| 9317 | 104416 | static bool post_recover_handlerton(THD *, plugin_ref plugin, void *) { | |
| 9318 | 104416 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 9319 | |||
| 9320 |
4/4✓ Branch 0 taken 104165 times.
✓ Branch 1 taken 251 times.
✓ Branch 2 taken 9493 times.
✓ Branch 3 taken 94672 times.
|
104416 | if (hton->state == SHOW_OPTION_YES && hton->post_recover) |
| 9321 | 9493 | hton->post_recover(); | |
| 9322 | |||
| 9323 | 104413 | return false; | |
| 9324 | } | ||
| 9325 | |||
| 9326 | 9493 | void ha_post_recover(void) { | |
| 9327 | 9493 | (void)plugin_foreach(nullptr, post_recover_handlerton, | |
| 9328 | MYSQL_STORAGE_ENGINE_PLUGIN, nullptr); | ||
| 9329 | 9490 | } | |
| 9330 | |||
| 9331 | 454 | void handler::ha_set_primary_handler(handler *primary_handler) { | |
| 9332 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 454 times.
|
454 | assert((ht->flags & HTON_IS_SECONDARY_ENGINE) != 0); |
| 9333 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 454 times.
|
454 | assert(primary_handler->table->s->has_secondary_engine()); |
| 9334 | 454 | m_primary_handler = primary_handler; | |
| 9335 | 454 | } | |
| 9336 | |||
| 9337 | /** | ||
| 9338 | Checks if the database name is reserved word used by SE by invoking | ||
| 9339 | the handlerton method. | ||
| 9340 | |||
| 9341 | @param plugin SE plugin. | ||
| 9342 | @param name Database name. | ||
| 9343 | |||
| 9344 | @retval true If the name is reserved word. | ||
| 9345 | @retval false If the name is not reserved word. | ||
| 9346 | */ | ||
| 9347 | 93365 | static bool is_reserved_db_name_handlerton(THD *, plugin_ref plugin, | |
| 9348 | void *name) { | ||
| 9349 | 93365 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 9350 |
4/4✓ Branch 0 taken 93322 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 15589 times.
✓ Branch 3 taken 77733 times.
|
93365 | if (hton->state == SHOW_OPTION_YES && hton->is_reserved_db_name) |
| 9351 | 15589 | return (hton->is_reserved_db_name(hton, (const char *)name)); | |
| 9352 | 77776 | return false; | |
| 9353 | } | ||
| 9354 | |||
| 9355 | /** | ||
| 9356 | Check if the database name is reserved word used by SE. | ||
| 9357 | |||
| 9358 | @param name Database name. | ||
| 9359 | |||
| 9360 | @retval true If the name is a reserved word. | ||
| 9361 | @retval false If the name is not a reserved word. | ||
| 9362 | */ | ||
| 9363 | 15589 | bool ha_check_reserved_db_name(const char *name) { | |
| 9364 | 15589 | return (plugin_foreach(nullptr, is_reserved_db_name_handlerton, | |
| 9365 | MYSQL_STORAGE_ENGINE_PLUGIN, | ||
| 9366 | 15589 | const_cast<char *>(name))); | |
| 9367 | } | ||
| 9368 | |||
| 9369 | /** | ||
| 9370 | Check whether an error is index access error or not | ||
| 9371 | after an index read. Error other than HA_ERR_END_OF_FILE | ||
| 9372 | or HA_ERR_KEY_NOT_FOUND will stop next index read. | ||
| 9373 | |||
| 9374 | @param error Handler error code. | ||
| 9375 | |||
| 9376 | @retval true if error is different from HA_ERR_END_OF_FILE or | ||
| 9377 | HA_ERR_KEY_NOT_FOUND. | ||
| 9378 | @retval false if error is HA_ERR_END_OF_FILE or HA_ERR_KEY_NOT_FOUND. | ||
| 9379 | */ | ||
| 9380 | 28316 | bool is_index_access_error(int error) { | |
| 9381 |
3/4✓ Branch 0 taken 28316 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19300 times.
✓ Branch 3 taken 9016 times.
|
28316 | return (error != HA_ERR_END_OF_FILE && error != HA_ERR_KEY_NOT_FOUND); |
| 9382 | } | ||
| 9383 | |||
| 9384 | 9547 | Xa_state_list::Xa_state_list(Xa_state_list::list &populated_by_tc) | |
| 9385 | 9547 | : m_underlying{populated_by_tc} {} | |
| 9386 | |||
| 9387 | 118 | enum_ha_recover_xa_state Xa_state_list::find(XID const &to_find) { | |
| 9388 |
1/2✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
|
118 | auto found = this->m_underlying.find(to_find); |
| 9389 |
1/2✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
|
118 | if (found != this->m_underlying.end()) return found->second; |
| 9390 | ✗ | return enum_ha_recover_xa_state::NOT_FOUND; | |
| 9391 | } | ||
| 9392 | |||
| 9393 | 389 | enum_ha_recover_xa_state Xa_state_list::add(XID const &xid, | |
| 9394 | enum_ha_recover_xa_state state) { | ||
| 9395 | 389 | auto previous_state = enum_ha_recover_xa_state::NOT_FOUND; | |
| 9396 | |||
| 9397 |
1/2✓ Branch 0 taken 389 times.
✗ Branch 1 not taken.
|
389 | auto it = this->m_underlying.find(xid); |
| 9398 |
2/2✓ Branch 0 taken 84 times.
✓ Branch 1 taken 305 times.
|
389 | if (it != this->m_underlying.end()) previous_state = it->second; |
| 9399 | |||
| 9400 |
2/4✓ Branch 0 taken 310 times.
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
389 | switch (state) { |
| 9401 | 310 | case enum_ha_recover_xa_state::PREPARED_IN_SE: { | |
| 9402 |
4/4✓ Branch 0 taken 39 times.
✓ Branch 1 taken 271 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 6 times.
|
310 | if (previous_state == enum_ha_recover_xa_state::NOT_FOUND || |
| 9403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
|
33 | previous_state == enum_ha_recover_xa_state::COMMITTED || |
| 9404 | previous_state == enum_ha_recover_xa_state::ROLLEDBACK) | ||
| 9405 |
1/2✓ Branch 0 taken 277 times.
✗ Branch 1 not taken.
|
277 | this->m_underlying[xid] = state; |
| 9406 | 310 | break; | |
| 9407 | } | ||
| 9408 | 79 | case enum_ha_recover_xa_state::PREPARED_IN_TC: { | |
| 9409 |
3/4✓ Branch 0 taken 45 times.
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 45 times.
|
79 | if (previous_state == enum_ha_recover_xa_state::NOT_FOUND || |
| 9410 | previous_state == enum_ha_recover_xa_state::PREPARED_IN_SE) | ||
| 9411 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | this->m_underlying[xid] = state; |
| 9412 | 79 | break; | |
| 9413 | } | ||
| 9414 | ✗ | case enum_ha_recover_xa_state::NOT_FOUND: | |
| 9415 | case enum_ha_recover_xa_state::COMMITTED: | ||
| 9416 | case enum_ha_recover_xa_state::COMMITTED_WITH_ONEPHASE: | ||
| 9417 | case enum_ha_recover_xa_state::ROLLEDBACK: { | ||
| 9418 | ✗ | assert(false); | |
| 9419 | break; | ||
| 9420 | } | ||
| 9421 | } | ||
| 9422 | 389 | return previous_state; | |
| 9423 | } | ||
| 9424 | |||
| 9425 | 7758 | Xa_state_list::instantiation_tuple Xa_state_list::new_instance() { | |
| 9426 | auto mem_root = | ||
| 9427 |
1/2✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
|
7758 | std::make_unique<MEM_ROOT>(PSI_INSTRUMENT_ME, tc_log_page_size / 3); |
| 9428 |
1/2✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
|
7758 | auto map_alloc = std::make_unique<Xa_state_list::allocator>(mem_root.get()); |
| 9429 |
1/2✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
|
7758 | auto xid_map = std::make_unique<Xa_state_list::list>(*map_alloc.get()); |
| 9430 |
1/2✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
|
7758 | auto xa_list = std::make_unique<Xa_state_list>(*xid_map.get()); |
| 9431 | return std::make_tuple< | ||
| 9432 | std::unique_ptr<MEM_ROOT>, std::unique_ptr<Xa_state_list::allocator>, | ||
| 9433 | std::unique_ptr<Xa_state_list::list>, std::unique_ptr<Xa_state_list>>( | ||
| 9434 | 7758 | std::move(mem_root), std::move(map_alloc), std::move(xid_map), | |
| 9435 |
1/2✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
|
23274 | std::move(xa_list)); |
| 9436 | 7758 | } | |
| 9437 |